RxSwift - 无法绑定自定义UICollectionViewCell的变量

时间:2018-01-29 15:47:54

标签: ios swift rx-swift

我有一个自定义UICollectionViewCell,里面有UILabel。 还有属性hour,为了示例,它是String?

我创建了一个名为bind的私有函数来配置我的绑定。这是我的班级:

class HourCollectionViewCell: UICollectionViewCell {
    @IBOutlet weak var hourLabel UILabel!
    let hour Variable<String?> = Variable<String?>("")
    let disposeBag: DisposeBag = DisposeBag()

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        bind()
    }

    private func bind() {
        hour.asObservable().bind(to: hourLabel.rx.text).disposed(by: disposeBag)
        hour.asObservable().subscribe(onNext: {debugPrint("New hour: \($0 ?? "--")")}).disposed(by: disposeBag)
    }
}

在所需的init中调用bind可能是个问题。有时hourLabel仍未初始化。此外,在init(frame: CGRect)内调用此函数永远不会触发bind函数,这很尴尬。我以为这个函数总是被调用。

即使这是一个简单的绑定,我也无法正确实现。

从我的UICollectionViewController内部,我有这个函数填充我的自定义单元格中的hour属性:

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "HourCollectionViewCell", for: indexPath) as! HourCollectionViewCell
        var text: String = "\(indexPath.row)"

        // This does not work because `bind` method
        // is never called.
        cell.hour.value = text

        return cell
    }

更新 我已经看到当我从故事板初始化视图时调用init:coder,就是这种情况。

我见过here的解决方法是从bind内拨打layoutSubviews。一切顺利。这是更好的方法吗?

1 个答案:

答案 0 :(得分:2)

您的手机电池是可重复使用的,因此您应该清理处理袋。

class HourCollectionViewCell: UICollectionViewCell {
    @IBOutlet weak var hourLabel UILabel!
    let hour = PublishRelay<String?>()
    private(set) var disposeBag = DisposeBag()

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    func bind() {
        hour.asDriver(onErrorJustReturn: "").debug().drive( hourLabel.rx.text).disposed(by: disposeBag)
    }

    override prepareForReuse() {
        super.prepareForReuse()
        disposeBag = DisposeBag()
    }
}

我使用了PublishRelay因为Variable已被弃用,并将其设为Driver以确保我们位于mainThread上。 您可以使用debug()在控制台中打印事件。

因为在重用时我们清除了disposeBag,我们可以在UICollectionViewController中调用bind:

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "HourCollectionViewCell", for: indexPath) as! HourCollectionViewCell
        var text: String = "\(indexPath.row)"

        cell.bind()
        cell.hour.accept(text)

        return cell
    }

我建议您查看RxDataSources,因为UICollectionViewController可能更适合为每个单元格提供模型。

相关问题