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

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

  •  
  •   nannanziyu · 2017-10-12 15:23:55 +08:00 · 4521 次点击
    这是一个创建于 2359 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

    S1

    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)
    

    S1

    6,Xcode8.3.3 + Swift3

    目前尚无回复
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1127 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 22:54 · PVG 06:54 · LAX 15:54 · JFK 18:54
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.