
开发过程中遇到的,发出来和大家一起讨论。
新建了一个简单的 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