HTML5   发布时间:2022-04-27  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了ios – 使用“拳击”式的多重绑定和处理大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
这是一个非常具体和长期的问题,但我不够聪明,不能自己解决这个问题.

我对来自raywenderlich.com的this YouTube-video非常感兴趣,它使用“拳击”方法来观察一个值.

他们的Box看起来像这样

class Box<T> {
    typealias Listener = T -> Void
    var listener: Listener?

    var value: T {
        didSet {
            listener?(value)
        }
    init(_ value: T) {
        self.value = value
    }
    func bind(listener: Listener?) {
        self.listener = listener
        listener?(value)
    }
}

很明显,每个“盒子”只允许一个听众.

let bindable:Box<String> = Box("Some text")
bindable.bind { (text) in
    //This will only be called once (from initial setup)
}
bindable.bind { (text) in
    // - because this listener has replaced it. This one will be called when value changes.
}

只要设置了这样的绑定,就会释放先前的绑定,因为Box用新的侦听器替换了侦听器.

我需要能够从不同的地方观察到相同的价值.我像这样重写了Box

class Box<T> {
    typealias Listener = (T) -> Void
    var listeners:[Listener?] = []

    var value:T{
        didSet{
            listeners.forEach({$0?(value)})
        }
    }
    init(_ value:T){
        self.value = value
    }
    func bind(listener:Listener?){
        self.listeners.append(listener)
        listener?(value)
    }
}

然而 – 这也给我带来了麻烦,显然..有些地方我希望新绑定删除旧绑定.例如,如果我从可重用的UITableViewCell中观察对象中的值,则在滚动时它将被绑定多次.我现在需要一种受控制的方式来处理特定的绑定.

我试图通过将此函数添加Box解决此问题:

func freshBind(listener:Listener?){
    self.listeners.removeAll()
    self.bind(listener)
}

在某种程度上起了作用,我现在可以使用freshBind({}),只要我想删除旧的侦听器,但这也不是我想要的.我在观察UITableViewCells的值时必须使用它,但我还需要从其他地方观察相同的值.一旦细胞被重复使用,我就会移除旧的观察者以及我需要的其他观察者.

我现在有信心我需要一种方法来保留一个一次性物品,无论我以后想要处理它们.

我不够聪明,不能自己解决这个问题,所以我需要帮助.

我几乎没有使用过一些反应式编程框架(比如reactiveCocoa),我现在明白为什么他们的订阅会返回我必须保留的Disposable对象并在需要时处理掉.我需要这个功能.

我想要的是:func bind(listener:Listener?) – > Disposable {}

我的计划是创建一个名为Disposable的类,其中包含(可选)侦听器,并将侦听器:[Listener?]转换为侦听器:[Disposable],但我遇到了< T>的问题.

无法将’Box< String?> .Disposable’类型的值转换为预期参数类型’Box< Any> .Disposable’

任何聪明的建议?

解决方法

我想解决这个问题的方法是给每个观察者一个唯一的标识符(比如UUID)并使用它来允许Disposable在时间上删除观察者.例如:

import Foundation

// A Disposable holds a `dispose` closure and calls it when it is released
class Disposable {
    let dispose: () -> Void
    init(_ dispose: @escaping () -> Void) { self.dispose = dispose }
    deinit { dispose() }
}

class Box<T> {
    typealias Listener = (T) -> Void

    // replace your array with a Dictionary mapping
    // I also made the Observer method mandatory. I don't believe it makes
    // sense for it to be optional. I also made it private.
    private var listeners: [UUID: Listener] = [:]

    var value: T {
        didSet {
            listeners.values.forEach { $0(value) }
        }
    }

    init(_ value: T){
        self.value = value
    }

    // Now return a Disposable. You'll get a warning if you fail
    // to retain it (and it will immediately be destroyed)
    func bind(listener: @escaping Listener) -> Disposable {

        // UUID is a nice way to create a unique identifier; that's what it's for
        let identifier = UUID()

        // Keep track of it
        self.listeners[identifier] = listener

        listener(value)

        // And create a Disposable to clean it up later. The Disposable
        // doesn't have to kNow anything about T. 
        // Note that Disposable has a strong referene to the Box
        // This means the Box can't go away until the last observer has been removed
        return Disposable { self.listeners.removeValue(forKey: identifier) }
    }
}

let b = Box(10)

var disposer: Disposable? = b.bind(listener: { x in print(X)})
b.value = 5
disposer = nil
b.value = 1

// Prints:
// 10
// 5
// (Doesn't print 1)

这可以很好地扩展到像DisposeBag这样的概念:

// Nothing but an array of Disposables.
class DisposeBag {
    private var disposables: [Disposable] = []
    func append(_ disposable: DisposablE) { disposables.append(disposablE) }
}

extension Disposable {
    func disposed(by bag: DisposeBag) {
        bag.append(self)
    }
}

var disposeBag: DisposeBag? = DisposeBag()

b.bind { x in print("bag: \(X)") }
    .disposed(by: disposeBag!)

b.value = 100
disposeBag = nil
b.value = 500

// Prints:
// bag: 1
// bag: 100
// (Doesn't print "bag: 500")

很高兴自己构建一些这样的东西,以便了解它们的工作方式,但对于严肃的项目,这通常不够.主要问题是它不是线程安全的,所以如果在后台线程上处理某些东西,你可能会破坏整个系统.你当然可以使它成为线程安全的,并不是那么困难.

但后来你意识到你真的想要组成听众.您需要一个监听另一个监听器并转换它的监听器.所以你建立地图.然后你意识到你想要过滤值设置为旧值的情况,所以你建立一个“只发送给我不同的值”,然后你意识到你想要过滤器来帮助你,然后….

你意识到你正在重建RxSwift.

这根本不是避免编写自己的东西的原因,而且RxSwift包含许多项目从不需要的大量功能(可能太多功能),但随着你的进展,你应该继续问自己“我应该切换到RxSwift现在?”

大佬总结

以上是大佬教程为你收集整理的ios – 使用“拳击”式的多重绑定和处理全部内容,希望文章能够帮你解决ios – 使用“拳击”式的多重绑定和处理所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。