在嵌套范围中将委托分配给NSOpenPanel会导致EXC_BAD_ACCESS

时间:2016-04-13 04:21:43

标签: objective-c swift cocoa

考虑以下简化代码示例。它在Swift中提供,但在objective-c中也会出现相同的行为。

import Foundation
import Cocoa
class MainWindow : NSWindow {
    @IBAction func onClick_openFile(sender : AnyObject?) {
        let path = runOpenPanel(false);
        NSLog(path as String)
    }

    @IBAction func onClick_crashyByeBye(sender : AnyObject?) {
        let path = runOpenPanel(true);
        NSLog(path as String)
    }

    private func runOpenPanel(useCrashyDelegate : Bool) -> NSString {
        let openPanel = NSOpenPanel.init()
        openPanel.canChooseDirectories = false
        openPanel.canChooseFiles = true
        openPanel.allowsMultipleSelection = false

        let safeDelegate = MyOpenPanelDelegate.init() //same scope as openPanel.runModal()--works fine
        if (useCrashyDelegate) {
            let crashyDelegate = MyOpenPanelDelegate.init() //falls out of scope before openPanel.runModal() and crashes
            openPanel.delegate = crashyDelegate
        } else {
            openPanel.delegate = safeDelegate
        }

        if (openPanel.runModal() == NSFileHandlingPanelOKButton && openPanel.URLs.count == 1) {
            return openPanel.URLs[0].path!
        }

        return ""
    }
}

class MyOpenPanelDelegate : NSObject, NSOpenSavePanelDelegate { 
    func panel(sender: AnyObject, shouldEnableURL url: NSURL) -> Bool {
        var isDir : ObjCBool = false
        if (NSFileManager.defaultManager().fileExistsAtPath(url.path!, isDirectory: &isDir)) {
            return isDir || (url.path! as NSString).lastPathComponent.lowercaseString == "foo.txt"
        }
        return false
    }
}

useCrashyDelegate的{​​{1}}参数为真时,runOpenPanel在嵌套范围内实例化,并且在调用crashyDelegate之前超出范围。由于open面板将crashyDelegate指定为其委托,因此我希望openPanel.runModal()引用计数增加。但是,当crashyDelegate's为真时,应用程序会以EXC_BAD_ACCESS崩溃。如果useCrashyDelegate为false,则会在与useCrashyDelegate的调用相同的范围内实例化safeDelegate,并将其分配给开放面板,并且没有openPanel.runModal()

这让我相信NSOpen EXC_BAD_ACCESS anel并没有增加其代表的引用计数。这是预期的行为,还是这可能是一个错误?

1 个答案:

答案 0 :(得分:1)

  

这让我相信NSOpenPanel没有增加其委托的引用计数。这是预期的行为,还是这可能是一个错误?

预计。检查属性的类型,您将看到它是assign(Objective-C)或unsafe(Swift),不保留强引用。这是Cocoa代表的常见设计模式。

HTH