我正在尝试将数据从 UITableView 函数 cellForRowAt 传递到自定义 UITableViewCell。该单元构造一个 UIStackView,其中包含 n 个 UIView。 n 是数组中项目的计数,并且取决于假设要传输的数据(该数组中的项目计数)。我在这里发生了一些非常困惑的事情。我已经使用以下代码片段检查了数据已成功通过的 tableView 的 VC
print("SELECTED EXERCISES: ", self.selectedExercises)
cell.randomSelectedExercises = self.selectedExercises
print("PRINTING FROM CELL: ", cell.randomSelectedExercise)
我可以确认这两个打印语句都返回非空数组。所以对我来说,这意味着自定义单元格具有我要求它具有的数据。但是,当我尝试在 UITableViewCell swift 文件 (randomSelectedExercises) 中打印出完全相同的数组时,它返回空给我。这怎么可能?据我了解,该单元格首先致力于创建属性初始值设定项,然后“自我”可用。我之前有一个错误告诉我这个并修复它,我将我的 UIStackView 初始值设定项设置为惰性,但这就是我解决当前问题的方式。
这是与表视图相关的问题相关的开头代码。我决定展示这段代码,以防问题不在我的单元格中,而是在我的表格视图代码中:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "RoutineTableViewCell") as! RoutineTableViewCell
let workout = selectedWorkouts[indexPath.row]
//get the information we need - just the name at this point
let name = workout["name"] as! String
var randomInts = [Int]()
//perform a query
let query = PFQuery(className: "Exercise")
query.includeKey("associatedWorkout")
//filter by associated workout
query.whereKey("associatedWorkout", equalTo: workout)
query.findObjectsInBackground{ (exercises, error) in
if exercises != nil {
//Created an array of random integers... this code is irrelevant to the question
//Picking items from parent array. selectedExercises is a subarray
for num in randomInts {
//allExercises just contains every possible item to pick from
self.selectedExercises.append(self.allExercises[num-1])
}
//now we have our selected workouts
//Both print statements successfully print out correct information
print("SELECTED EXERCISES: ", self.selectedExercises)
cell.randomSelectedExercises = self.selectedExercises
print("PRINTING FROM CELL: ", cell.randomSelectedExercises)
//clear the arrays so we have fresh ones through each iteration
self.selectedExercises.removeAll(keepingCapacity: false)
self.allExercises.removeAll(keepingCapacity: false)
} else {
print("COULD NOT FIND WORKOUT")
}
}
//***This works as expected - workoutName is visible in cell***
cell.workoutName.text = name
//clear the used arrays
self.allExercises.removeAll(keepingCapacity: false)
self.selectedExercises.removeAll(keepingCapacity: false)
return cell
}
下面是在单元格 swift 文件中给我一个问题的代码。当我进入这个区域时,randomSelectedExercise
里面没有任何数据。这是一个问题,因为在我的 for 循环中,我从 1 迭代到 randomSelectedExercise.count。如果此值为 0,我会收到错误消息。问题集中在 UIStackView 初始值设定项中:
import UIKit
import Parse
//Constants
let constantHeight = 50
//dynamic height number
var heightConstantConstraint: CGFloat = 10
class RoutineTableViewCell: UITableViewCell {
//will hold the randomly selected exercises that need to be displayed
//***This is where I thought the data would be saved, but it is not... Why???***
var randomSelectedExercises = [PFObject]()
static var reuseIdentifier: String {
return String(describing: self)
}
// MARK: Overrides
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
private func commonInit() {
contentView.addSubview(containerView)
containerView.addSubview(workoutName)
containerView.addSubview(stackView)
NSLayoutConstraint.activate(staticConstraints(heightConstantConstraint: heightConstantConstraint))
//reset value
heightConstantConstraint = 10
}
//MARK: Elements
//Initializing workoutName UILabel...
let workoutName: UILabel = {...}()
//***I RECEIVE AN EMPTY ARRAY IN THE PRINT STATEMENT HERE SO NUM WILL BE 0 AND I WILL RECEIVE AN ERROR IN THE FOR LOOP***
lazy var stackView: UIStackView = {
let stackView = UIStackView()
stackView.backgroundColor = .gray
stackView.translatesAutoresizingMaskIntoConstraints = false
//not capturing the data here
print("rSE array:", randomSelectedExercises)
var num = randomSelectedExercises.count
for i in 1...num {
let newView = UIView(frame: CGRect(x: 0, y: (i*50)-50, width: 100, height: constantHeight))
heightConstantConstraint += CGFloat(constantHeight)
newView.backgroundColor = .purple
let newLabel = UILabel(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
newLabel.text = "Hello World"
newView.addSubview(newLabel)
stackView.addSubview(newView)
}
return stackView
}()
//initializing containerView UIView ...
let containerView: UIView = {...}()
//Setting the constraints for each component...
private func staticConstraints(heightConstantConstraint: CGFloat) -> [NSLayoutConstraint] {...}
}
为什么我的数据没有正确传输?如何正确传输数据?
您遇到的问题是 findObjectsInBackground
中的 tableView(_:cellForRowAt:)
完成处理程序中的代码正在异步执行。这意味着当在处理程序中设置 cell.randomSelectedExercise
s 时,lazy var stackView: UIStackView
已经用默认值初始化,这是一个空数组。
要解决此问题,您应该在加载 randomSelectedExercises
后重新加载表视图数据。您可以通过向 loadSelectedExercises(for:completion:)
方法添加一个完成块以在数据已加载时通知调用者然后在完成块中的表视图上调用 reloadData()
来实现此目的。
这是您可以进行的更改的示例实现:
// Update the loadSelectedExercises method to accept a completion block
func loadSelectedExercises(for workout: PFObject, completion: @escaping ([PFObject]?, Error?) -> Void) {
let query = PFQuery(className: "Exercise")
query.includeKey("associatedWorkout")
query.whereKey("associatedWorkout", equalTo: workout)
query.findObjectsInBackground { (exercises, error) in
if let exercises = exercises {
completion(exercises, nil)
} else {
completion(nil, error)
}
}
}
// In tableView(_:cellForRowAt:), call loadSelectedExercises with a completion block to reload the table view data once the exercises have been loaded
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "RoutineTableViewCell", for: indexPath) as! RoutineTableViewCell
let workout = selectedWorkouts[indexPath.row]
let name = workout["name"] as! String
loadSelectedExercises(for: workout) { exercises, error in
if let exercises = exercises {
self.selectedExercises = exercises
cell.randomSelectedExercises = exercises
cell.configureStackView()
tableView.reloadData()
} else if let error = error {
print("Error loading exercises: \(error.localizedDescription)")
}
}
cell.workoutName.text = name
return cell
}
// Update the RoutineTableViewCell class to include a configureStackView method that sets up the stack view based on the randomSelectedExercises array
class RoutineTableViewCell: UITableViewCell {
var randomSelectedExercises = [PFObject]()
...
func configureStackView() {
let num = randomSelectedExercises.count
for i in 1...num {
...
}
}
}
在此示例中,将更新 loadSelectedExercises(for:completion:)
以接受加载练习时调用的完成块。 tableView(_:cellForRowAt:)
现在使用设置单元格 randomSelectedExercises
属性的完成块调用此方法,调用 configureStackView()
以基于 randomSelectedExercises 数组设置堆栈视图,然后在加载练习后重新加载表视图数据。
在 configureStackView()
中添加 RoutineTableViewCell
方法,用于根据 randomSelectedExercises
数组设置堆栈视图。这个方法在 loadSelectedExercises(for:completion:).