【问题标题】:Accessing self from instance properties which are closures从作为闭包的实例属性访问 self
【发布时间】:2014-08-09 21:43:11
【问题描述】:

我使用的是 Xcode6-beta2,但自从第一次公开测试版以来我就遇到了同样的问题。我的 Obj-C UIViewController 的 Swift 子类如下所示:

class SomeVC: UIViewController {
    var c1: () -> () = {
        println(self)
    }

    var c2: () -> () {
        get {
            return { println(self) }
        }
    }

    var c3: () -> () {
        return { println(self) }
    }

    override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)
        c1()
        c2()
        c3()
    }
}

显示 VC 时,我看到打印出以下几行:

(Function)
<_TtC12SwiftiOSTest6SomeVC: 0x10bf1ed10>
<_TtC12SwiftiOSTest6SomeVC: 0x10bf1ed10>

(c2 和 c3 的不同之处仅在于,如果计算属性只是可获取的,则不需要包含 get {...}。)

所以,第一个闭包的 self 似乎是指函数/闭包类型本身,而其他的 self 指的是视图控制器(正如我所料)。 c1 和 c2/c3 之间的唯一区别是前者是存储属性,后者是计算属性,但我仍然希望闭包和它们捕获的值是相同的,即 self 总是参考封闭类。现在的情况,似乎没有明显的方法让 c1 闭包访问封闭类的方法/属性。

这是某处记录的内容(我阅读了 Swift 书,但没有找到任何内容),还是只是某种 beta 编译器错误,应该在某处提交?

【问题讨论】:

    标签: swift


    【解决方案1】:

    这看起来很有趣,所以我再深入一点。发现,您可以像self.instanceVariable 一样访问闭包内的类实例变量。然后闭包将捕获其中的self。所以现在self 指的是类实例本身。你的闭包应该是一个 lazy 属性。

    惰性属性意味着您可以在默认闭包中引用 self,因为在初始化完成并且知道 self 存在之前,不会访问惰性属性。

    您缺少 @lazy,因此 self 对闭包是未知的,这就是为什么它将它打印为 (Function) 我的猜测。

    class TableViewController: UIViewController {
    var name = "anil"
    // Since swift 2.0 came out @lazy is replaced by lazy
    lazy  var c1: () -> () = {
        println(self)
        println(self.name)
    
    }
    
    var c2: () -> () {
    get {
        return { println(self) }
    }
    }
    
    var c3: () -> () {
    return { println(self) }
    }
    
    
      override func viewDidLoad() {
            super.viewDidLoad()
            c1()
            c2()
            c3()
            }
    }
    

    输出

    <_ttc12tableviewapp19tableviewcontroller:>
    阿尼尔
    <_ttc12tableviewapp19tableviewcontroller:><_ttc12tableviewapp19tableviewcontroller:>


    更新

    将闭包分配给类实例变量会导致强引用循环。你应该避免这种情况。 Swift 使用 捕获列表

    如果您将闭包分配给类实例的属性,并且闭包通过引用实例或其成员来捕获该实例,您将在闭包和实例之间创建一个强引用循环。 Swift 使用捕获列表来打破这些强引用循环。如需更多信息,请参阅Strong Reference Cycles for Closures

    所以闭包的正确用法应该是

    @lazy  var c1: () -> () = {
        [unowned self] in
        println(self)
        println(self.name)
    
    }
    

    参考:Swift programming guide

    编辑
    @lazy已更改为lazy

    【讨论】:

    • 我试过了,我得到了这个编译器错误:'SomeVC -> () -> SomeVC!'没有名为“name”的成员。 但是,您的代码在另一个方面与我的不同 - @lazy 关键字/指令/不管它是什么。当我在 c1 闭包定义之前添加它时,它可以工作,我什至不需要 name 变量。这就更让人迷惑了,lazy init 跟这里有什么关系?
    • 所以这看起来像是一个编译器错误,不是吗?
    • 不需要实例变量这是我的误解。您可以省略变量。但@lazy 是必需的。
    • 好的,我在 Apple 的 Swift 书中找到了这段摘录,所以这是一个无编译器问题。非常非常令人困惑。感谢您帮助解决这个问题。
    • 是的,我知道这一点,我的代码实际上并没有使用强引用自我(我使用 [weak self] 因为 unowned 在我身上爆炸了,不知道为什么。我需要阅读ARC 章节。我没有在我的原始帖子中使用它来使事情变得更容易,以尽量减少混乱。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-24
    • 2021-05-24
    • 1970-01-01
    • 2016-11-30
    相关资源
    最近更新 更多