Swift3,你必须把这个弱变量装箱是正确的吗?

Swift3, is it correct that you have to box this weak variable?

关于装箱弱引用的通常过程,我有四个晦涩难懂的问题。

为了演示这些问题,这里有一个通知系统,Notes

你会像这样使用它...

class SyncedCell: UITableViewCell, Notes {

    override func layoutSubviews() {
        ...
        listen(forNote: "soloCell")
    }
    func editing() {
        say(note: "soloCell")
        ...
        input.becomeFirstResponder()
    }
    func note() {
        print("Hooray, I got a note..")
        editingCancel()
    }

因此,Notes 的代码如下。

对于给定的键(例如 "soloCell"),您只需 保留一个数组 对任何对象的引用,这些对象希望在调用该键时获取消息。

当然,这些必须是弱引用

所以,当一个新对象到达需要在列表中记忆时...

    var b:_Box = _Box()
    b.p = self
    _notes[k]?.append(b)

("listen" 函数只是将该对象添加到该键的项目列表中。"say" 函数遍历该键的监听项目列表:对于每个项目 - 如果项目在此期间没有消失 - 它发送了一条消息。)

所以!据我所知,你不能保留弱引用数组

您必须将它们装箱,如下面的代码所示。

  1. 真的吗?使用盒子很难看,有没有办法简单地保留一个弱引用列表?无需装箱?

  2. 相关:在kodes中AnyObject是基础。那是最好的吗?

  3. 注意协议是不是: class。这令人不安,我不确定是否应该如此。

  4. 请注意,非常不幸的是,在 Swift 中——据我所知——你无法观察到指向 nil 的弱引用。 2017年还是这样吗?有什么办法可以做到这一点吗?

脚注 - 关于第 4 点,"is there any way to achieve this?" 唯一的可能性似乎是将 associatedPbject 添加到监视的项目。 (例子)[

代码...

struct _Box {
    weak var p: AnyObject?
    // note: I prefer to spell out the assigment,
    // rather than have a convenience initializer here
}

var _notes:[String:[_Box]] = [:]

protocol Notes {
    func note()
}

extension Notes where Self:AnyObject {

func listen(forNote k: String) {
    if _notes.index(forKey: k) == nil {
        _notes[k] = []
    }
    var b:_Box = _Box()
    b.p = self
    _notes[k]?.append(b)
}

func say(note k:String) {
    if let _n = _notes[k] {
        var k:Int = 0
        print("notes.4            saying......")
        for b in _n {
            let p = b.p
            if (p == nil) {
                print("\(k) notes.4            there's one that's been removed")
            }
            else {
                print("\(k) notes.4            sending ok...")
                (p as! Notes).note()
            }
            k = k + 1
        }
    }
    __noteCleaner()
}

func __noteCleaner() {
    for var (k, _n) in _notes {
        let kn = _n.count
        for i in (0..<kn).reversed() {
            let p = _n[i].p
            if (p == nil) {
                _n.remove(at: i)
                let newk = _n.count
                print("notes.4, removed a dud listener for key \(k) new length is \(newk)")
            }
        }
        if (_n.count == 0) {
            print("notes.4, removed a seemingly unused key \(k)")
            _notes.removeValue(forKey: k)
        }
    }
}

}

我会专注于问题的核心。

您正在尝试通过在主题上注册观察者来实现观察者(侦听器)模式。我猜对象然后会手动调用每个观察者。

有一种更简单的方法可以实现这一点。您可以使用 单例 。观察者将在单身人士处注册,当有重要事情发生时,主题将通知单身人士。

为此有特殊的class,NotificationCenter。它只会保留无主引用。

代表不是为一个观察员设立的,也不是为多个观察员设立的。

当然,有一种简单的方法可以通过将引用包装到 struct/object 中来实现弱引用数组,请参阅 How do I declare an array of weak references in Swift?。我想这就是你的 Box 在做什么?

但是,我不知何故认为您的问题是由您的体系结构引起的。您将视图 classes 与模型 classes 混合在一起,这不是一个好主意。

具体回答您的问题:

  1. 没有。我相信 Swift 邮件列表中关于此的讨论以 "you can wrap it" 结束。您不必如此简单地包装它。您可以编写自己的数组版本,在内部进行包装。

  2. 使用泛型而不是 AnyObject,请参阅上面的链接问题。

  3. 是的,这令人不安。这是可能的,因为您实际上只在 AnyObject(即 classes)上使用它,并且您正在删除 Box 中的类型。 Box.P 声明为 Note 除非 Note 是一个 class 协议,否则这将不起作用。

  4. 这是正确的。参见 Know when a weak var becomes nil in Swift?。一个简单的解决方法是在解除分配侦听器时手动删除侦听器(在 deinit 中)。