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" 函数遍历该键的监听项目列表:对于每个项目 - 如果项目在此期间没有消失 - 它发送了一条消息。)
所以!据我所知,你不能保留弱引用数组。
您必须将它们装箱,如下面的代码所示。
真的吗?使用盒子很难看,有没有办法简单地保留一个弱引用列表?无需装箱?
相关:在kodes中AnyObject
是基础。那是最好的吗?
注意协议是不是: class
。这令人不安,我不确定是否应该如此。
请注意,非常不幸的是,在 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 混合在一起,这不是一个好主意。
具体回答您的问题:
没有。我相信 Swift 邮件列表中关于此的讨论以 "you can wrap it" 结束。您不必如此简单地包装它。您可以编写自己的数组版本,在内部进行包装。
使用泛型而不是 AnyObject
,请参阅上面的链接问题。
是的,这令人不安。这是可能的,因为您实际上只在 AnyObject
(即 classes)上使用它,并且您正在删除 Box
中的类型。 Box.P
声明为 Note
除非 Note
是一个 class
协议,否则这将不起作用。
这是正确的。参见 Know when a weak var becomes nil in Swift?。一个简单的解决方法是在解除分配侦听器时手动删除侦听器(在 deinit
中)。
关于装箱弱引用的通常过程,我有四个晦涩难懂的问题。
为了演示这些问题,这里有一个通知系统,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" 函数遍历该键的监听项目列表:对于每个项目 - 如果项目在此期间没有消失 - 它发送了一条消息。)
所以!据我所知,你不能保留弱引用数组。
您必须将它们装箱,如下面的代码所示。
真的吗?使用盒子很难看,有没有办法简单地保留一个弱引用列表?无需装箱?
相关:在kodes中
AnyObject
是基础。那是最好的吗?注意协议是不是
: class
。这令人不安,我不确定是否应该如此。请注意,非常不幸的是,在 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 混合在一起,这不是一个好主意。
具体回答您的问题:
没有。我相信 Swift 邮件列表中关于此的讨论以 "you can wrap it" 结束。您不必如此简单地包装它。您可以编写自己的数组版本,在内部进行包装。
使用泛型而不是
AnyObject
,请参阅上面的链接问题。是的,这令人不安。这是可能的,因为您实际上只在
AnyObject
(即 classes)上使用它,并且您正在删除Box
中的类型。Box.P
声明为Note
除非Note
是一个class
协议,否则这将不起作用。这是正确的。参见 Know when a weak var becomes nil in Swift?。一个简单的解决方法是在解除分配侦听器时手动删除侦听器(在
deinit
中)。