NSThread detachNewThreadSelector: Crash only in release build in Xcode 7 + Swift 2.0

840 views Asked by At

I have a framework that calls back methods in the AppDelegate using detachNewThreadSelector: of NSThread, which looks something like this:

private func bridgeSelector(selector: String?, object: String?) {
        if selector != nil && responder != nil {
            dispatch_async(dispatch_get_main_queue(), {
                NSThread.detachNewThreadSelector(Selector(
                    selector!),
                    toTarget: self.responder!,
                    withObject: object
                )
            })
        }
    }

The responder is a var assigned to self in AppDelegate when the framework's class was initialized.

The application ran without problem in the debug build, but crashed at once when the above is called if it's in release build. (It also crashed when I turned off optimize in the release build.)

I'm using Xcode 7 beta and Swift 2.0. (I knew it's beta, but it's the only beta supports Swift 2.)

EDIT - I end up use closure instead of the detachNewThreadSelector:. Works in both builds.

2

There are 2 answers

0
Cai On BEST ANSWER

The solution I use to replace the above one is using Closure.

In the class of the framework, I declared a closure variable:

class FrameworkClass {

    public var methodOfAnotherClass: ((sender: AnyObject?) -> ())?

    func asyncMethod() {
        // Done with the work.
        let msg = "From Russia, with love."
        methodOfAnotherClass!(sender: msg)
    }
}

Then in the main class:

class main {

    func bond(objectFromRussia: AnyObject?) {
        if let msg = objectFromRussia as? String {
            Swift.print(msg)
        }
    }

    func callMeMaybe() {
        let aFrameworkClassObject = FrameworkClass()
        aFrameworkClassObject.methodOfAnotherClass = bond
        aFrameworkClassObject.asyncMethod()
    }

}

When callMeMaybe: is called, console should print From Russia, with love.

6
B.S. On

Try adding respondsToSelector: check there. It is dirty, but something like that. It is dirty i believe

func bridgeSelector(selector: String?, object: String?) {
    if let r = responder, let sel = selector where
        r.respondsToSelector(Selector(sel))
    {
        dispatch_async(dispatch_get_main_queue(), {
            NSThread.detachNewThreadSelector(
                Selector(sel),
                toTarget: r,
                withObject: object
            )
        })
    }
}