从您可以编写任何代码的想法中获得灵感,我尝试了一个复杂的CollectionView嵌套结构,该结构如下:
CustomCollectionViewController
--CustomCollectionViewCell
----CustomTableView
------CustomTableViewCell
--------CustomPickerView
在 CustomCollectionViewController 中,主数据Feed来自属性:
var cardFeed: [String: [Card]] = [:]
Card 是我定义的模型,变量 cardFeed 在 UICollectionView < / strong>代理和数据源方法:
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "card", for: indexPath) as! CustomCollectionViewCell
cell.contentView.clipsToBounds = true
cell.delegate = self
cell.card = self.cardFeed[string]![indexPath.row]
cell.cardIndex = indexPath.row
}
通过委托方法,上面的cardFeed在 CustomCollectionViewCell 中设置了一个主要属性,用于更新接口:
var card: Card! {
didSet{
setupCard()
}
}
属性卡也是 UITableView 代理和数据源的数据馈送。
一切正常,一切都按原样显示。除了当用户从 CustomPickerView 中选择值时,主要数据供稿即 中定义的 cardFeed CustomCollectionViewController (如上所示)必须更新!
我的解决方法是:
(1)假定有三个组件,请定义一个数组,该数组记录 CustomPickerView 所选行中的更改,以及一个回调方法以向下传递变量:
var selectedRow: [Int] = [1, 0, 0] {
didSet {
if updateRow != nil {
updateRow!(self.selectedRow)
}
}
}
var updateRow: ( ([Int]) -> () )?
(2)在 CustomCollectionViewCell 中定义另一个回调,该回调带有一个额外的参数,以跟踪哪个单元格实际发送了选定的行数组:
var passSelectedRow: (([Int], Int) -> ())?
在tableViews cellForRowAtIndexPath方法中调用:
cell.updateRow = { selectedRow in
self.passSelectedRow!(selectedRow, indexPath.row)
}
(3)最终更新 CustomCollectionViewController 中的cardFeed:cellForItemAtIndexPath:
cell.passSelectedRow = { selectedRow, forIndex in
if self.cardFeed[string]![indexPath.row].chosenFood[forIndex].selectedRow != selectedRow {
self.cardFeed[string]![indexPath.row].chosenFood[forIndex].selectedRow = selectedRow
}
}
但这是问题所在,如果我现在将didSet添加到cardFeed,它将创建一个无限循环,因为cellForRowAtIndexPath将被无限期调用。如果我获得除cellForItemAtIndexPath以外的任何地方的 CustomCollectionViewCell 引用,则self.collectionView?.reload()不起作用!有什么办法可以从 CustomPickerView 中的选定行更新 CustomCollectionViewController 中的变量cardFeed?
答案 0 :(得分:1)
在对象之间进行通信时,不明智的做法是使子对象对其所有者有强烈的引用,这就是最终导致保留周期和错误的原因。
让我们看一下对象之间最常见的两种通信方式:委托和通知。
有代表团:
在您的示例中,创建用于传达所需信息的协议:
protocol PickerFoodSelectedDelegate : class {
func selected(row : Int, forIndex : Int)
}
在选择器类中添加weak var selectionDelegate : PickerFoodSelectedDelegate
作为变量
在tableView类中,在cellForItemAtIndexPath
期间,将self
分配给picker.selectionDelegate
然后,您将创建一个类似的结构以在表和集合视图之间进行通信。
关键部分是将委托引用声明为weak
,以避免保留周期和错误。
有了通知,您可以使用NotificationCenter.default
向您想要的任何对象发布通知,在这种情况下,您可以:
订阅您在表视图中选择的通知名称。
在选择选项后从选择器视图发布通知。
表收到通知后,提取对象。
从表到集合视图执行相同的操作。
希望这会有所帮助!