V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
WildCat
V2EX  ›  Swift

对闭包函数的强引用问题

  •  1
     
  •   WildCat · 2014-11-18 23:04:39 +08:00 · 3616 次点击
    这是一个创建于 3660 天前的主题,其中的信息可能已经有所发展或是发生改变。
    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: (() -> ())?
    这种情况下的最佳实践应该是什么?

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

    没有增加耦合吧
    jakwings
        4
    jakwings  
       2014-11-19 12:52:00 +08:00   ❤️ 1
    @WildCat apartment 直接调用了 person 的 method,而不是让 person 去调用,明显是越权了。而且强弱引用只能应用到 class 上面,你也没有什么别的办法了。在调用的时候,虽然函数使用的 self 依然是指向 person,但是总感觉怪怪的,不知道 self 能否保证永远指向 person,官方教程上貌似没有说到。
    WildCat
        5
    WildCat  
    OP
       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
        6
    jakwings  
       2014-11-19 19:13:03 +08:00   ❤️ 1
    @WildCat method 虽然也是函数,可它是属于对象/实例的,你可以让一个固定的 method 对 self 进行 unowned 吗?假如不行的话,就和相应对象/实例脱不了身了。可以考虑把那个 method 用 closure 替代,在初始化时添加好,不绑死在对象上。
    jakwings
        7
    jakwings  
       2014-11-19 19:42:40 +08:00
    对了,我这测试怎么也没 output,deinit 函数里的 println 好像没用,我改用全局变量 count 统计了。

    http://code.bulix.org/ijoun1-87439
    jakwings
        8
    jakwings  
       2014-11-19 19:47:41 +08:00
    @jakwings 看来不故意设置变量为 nil 的话 deinit 里的输出是会被抛弃的,不知道这算不算是 bug,或者说程序是在释放了 println 函数之后才开始对象的销毁操作……
    WildCat
        9
    WildCat  
    OP
       2014-11-19 20:04:21 +08:00   ❤️ 1
    @jakwings 不能用 Playground , Playground 会自动引用全局的对象。
    jakwings
        10
    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
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1028 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 20:07 · PVG 04:07 · LAX 12:07 · JFK 15:07
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.