如何在Swift

时间:2018-06-28 14:33:00

标签: ios swift xcode

从您可以编写任何代码的想法中获得灵感,我尝试了一个复杂的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?

1 个答案:

答案 0 :(得分:1)

在对象之间进行通信时,不明智的做法是使子对象对其所有者有强烈的引用,这就是最终导致保留周期和错误的原因。

让我们看一下对象之间最常见的两种通信方式:委托和通知。

有代表团:

  • 在您的示例中,创建用于传达所需信息的协议:

    protocol PickerFoodSelectedDelegate : class {
    
        func selected(row : Int, forIndex : Int)
    
    }
    
  • 在选择器类中添加weak var selectionDelegate : PickerFoodSelectedDelegate作为变量

  • 在tableView类中,在cellForItemAtIndexPath期间,将self分配给picker.selectionDelegate

  • 然后,您将创建一个类似的结构以在表和集合视图之间进行通信。

关键部分是将委托引用声明为weak,以避免保留周期和错误。

有了通知,您可以使用NotificationCenter.default向您想要的任何对象发布通知,在这种情况下,您可以:

  • 订阅您在表视图中选择的通知名称。

  • 在选择选项后从选择器视图发布通知。

  • 表收到通知后,提取对象。

  • 从表到集合视图执行相同的操作。

希望这会有所帮助!