請考慮以下簡化的代碼示例。它在Swift中介紹,但在Objective-C中發生相同的行爲。將委託分配給嵌套範圍中的NSOpenPanel原因EXC_BAD_ACCESS
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
參數runOpenPanel
是真實的,crashyDelegate
在嵌套範圍被實例化並調用openPanel.runModal()
之前超出範圍。由於打開的面板將crashyDelegate分配給它的委託,我期望crashyDelegate's
引用計數增加。但是,當useCrashyDelegate
爲真時,應用程序會崩潰EXC_BAD_ACCESS
。如果useCrashyDelegate
爲假,則在與調用openPanel.runModal()
相同範圍內實例化的safeDelegate
被分配給打開的面板,並且沒有EXC_BAD_ACCESS
。
這讓我相信NSOpen P
anel不會遞增其委託的引用計數。這是預期的行爲,還是這可能是一個錯誤?