Swift 开发遇到的一个莫名奇妙的 bug

2017-10-12 15:23:55 +08:00
 nannanziyu

开发过程中遇到的,发出来和大家一起讨论。
新建了一个简单的 Demo 也可以重现。
1,用 Xcode 新建一个新的 CocoaApplication,语言选 swift,使用 storyboard
2,往窗口上随便拖一个控件,比如 NSTableView,然后把 NSTableView 拉线到 ViewController,并命名为 tb
3,简单修改 ViewController,完整代码 gist 地址如下:
https://gist.github.com/anonymous/d0b2d458b58a74d9ef97307f0fa9f834

4,可以看到 Action 和 WhatEver 是除了名字外完全相同的两个类
在 menuWillOpen 里也是相似的两段代码,分别使用 Action 和 WhatEver 来创建 NSMenuItem 的 Action

5,奇怪的现象来了,同样的两个代码段顺序不同产生了不同的情形
5.1,情景 1

        let item2 = NSMenuItem()
        item2.title = "Item_2"
        let closure = WhatEver({print("xxx")})
        item2.target = closure
        item2.action = #selector(closure.invoke)
        objc_setAssociatedObject(self, String(format: "[%d]", arc4random()), closure, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
        menu.addItem(item2)
        
        let item1 = NSMenuItem()
        item1.title = "Item_1"
        let action = Action({print("xxx")})
        item1.target = action
        item1.action = #selector(action.action)
        objc_setAssociatedObject(self, String(format: "[%d]", arc4random()), action, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
        menu.addItem(item1)

ContextMenu 的两个子项第一次打开都是正常的,但是点过一次后,Item2 变灰

5.2,情景 2
将两块代码顺序互换,则一切正常

let item1 = NSMenuItem()
        item1.title = "Item_1"
        let action = Action({print("xxx")})
        item1.target = action
        item1.action = #selector(action.action)
        objc_setAssociatedObject(self, String(format: "[%d]", arc4random()), action, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
        menu.addItem(item1)
        
        let item2 = NSMenuItem()
        item2.title = "Item_2"
        let closure = WhatEver({print("xxx")})
        item2.target = closure
        item2.action = #selector(closure.invoke)
        objc_setAssociatedObject(self, String(format: "[%d]", arc4random()), closure, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
        menu.addItem(item2)

5.3,两段代码的 target 注释掉(这样闭包不会执行),无论哪段代码在前,Item2 都是灰色不可点

let item2 = NSMenuItem()
        item2.title = "Item_2"
        let closure = WhatEver({print("xxx")})
        //item2.target = closure
        item2.action = #selector(closure.invoke)
        objc_setAssociatedObject(self, String(format: "[%d]", arc4random()), closure, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
        menu.addItem(item2)
        
        let item1 = NSMenuItem()
        item1.title = "Item_1"
        let action = Action({print("xxx")})
        //item1.target = action
        item1.action = #selector(action.action)
        objc_setAssociatedObject(self, String(format: "[%d]", arc4random()), action, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
        menu.addItem(item1)

6,Xcode8.3.3 + Swift3

4566 次点击
所在节点    Swift
0 条回复

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

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

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

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

© 2021 V2EX