对闭包函数的强引用问题

2014-11-18 23:04:39 +08:00
 WildCat
class Person {
    func goHome() {
        println("test")
    }

    deinit {
        println("Persion deinit")
    }

}
class Apartment {
    var somebodyCome: (() -> ())?

    deinit {
        println("Apartment deinit")
    }
}

var person: Person? = Person()
var apartment: Apartment? = Apartment()

apartment!.somebodyCome = person!.goHome
person = nil
// Output: [nothing]

Apartment 引用了一个 Person的方法 goHome() 作为 somebodyCome 时的动作。
但是这会造成强引用。 不过无法写这样的语句 weak var somebodyCome: (() -> ())?
这种情况下的最佳实践应该是什么?

3510 次点击
所在节点    Swift
10 条回复
jakwings
2014-11-19 00:52:56 +08:00
为什么不引用 Person 而是引用函数?反正对象销毁的时候你也不需要那个函数了吧,而当函数还有用的时候对象也依然存在着。
jakwings
2014-11-19 01:03:49 +08:00
@jakwings 不对,我应该说你已经违反了面向对象编程的重要原则,增加了不必要的耦合度,没有让对象各施其职。
WildCat
2014-11-19 07:36:18 +08:00
@jakwings 没有吧,我这里的实际需求是,一个 Custom View 的发生变化的时候(类似 TabView 左滑动到上一页),通知Controller. 一般的做法是用 delegate + protocol ,这里我想直接用 Closure 。
但是我在 Controller 里打算用一个函数而不是闭包。主要是增加易读性。

没有增加耦合吧
jakwings
2014-11-19 12:52:00 +08:00
@WildCat apartment 直接调用了 person 的 method,而不是让 person 去调用,明显是越权了。而且强弱引用只能应用到 class 上面,你也没有什么别的办法了。在调用的时候,虽然函数使用的 self 依然是指向 person,但是总感觉怪怪的,不知道 self 能否保证永远指向 person,官方教程上貌似没有说到。
WildCat
2014-11-19 18:36:58 +08:00
@jakwings https://github.com/HeshamMegid/HMSegmentedControl/blob/master/HMSegmentedControlExample/HMSegmentedControlExample/ViewController.m

63~68 行:

既然在 Swift 中函数也是一等公民,我想把 indexChangeBlock 设置为 ViewController 的实例方法. 这样不合法吗?
jakwings
2014-11-19 19:13:03 +08:00
@WildCat method 虽然也是函数,可它是属于对象/实例的,你可以让一个固定的 method 对 self 进行 unowned 吗?假如不行的话,就和相应对象/实例脱不了身了。可以考虑把那个 method 用 closure 替代,在初始化时添加好,不绑死在对象上。
jakwings
2014-11-19 19:42:40 +08:00
对了,我这测试怎么也没 output,deinit 函数里的 println 好像没用,我改用全局变量 count 统计了。

http://code.bulix.org/ijoun1-87439
jakwings
2014-11-19 19:47:41 +08:00
@jakwings 看来不故意设置变量为 nil 的话 deinit 里的输出是会被抛弃的,不知道这算不算是 bug,或者说程序是在释放了 println 函数之后才开始对象的销毁操作……
WildCat
2014-11-19 20:04:21 +08:00
@jakwings 不能用 Playground , Playground 会自动引用全局的对象。
jakwings
2014-11-21 01:32:16 +08:00
@WildCat 那用 xcrun swift test.swift 执行呢?我这样做同样在程序结束时没有 deinit 的输出,在程序结束前自行设为 nil 就有。我觉得好像和全局对象无关吧?我在 SO 那里问了:
https://stackoverflow.com/questions/27044573/swift-no-output-for-println-in-deinit-method

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/147586

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX