Desultory crashes in my app since introducing Swift code

I ma getting a series of crashes on different targets on my app apprently not connected to any piece of code. As a matter of fact I am getting crahes on one target and a tester gets them on another target, but I do not know if the two things are connected. My crahes happen ever at different times and parts of my code and present themselves with:


Thread 1 Crashed:

0 libsystem_kernel.dylib 0x3a216808 kevent64 + 24

1 libdispatch.dylib 0x3a162de8 _dispatch_mgr_invoke + 228

2 libdispatch.dylib 0x3a151f6e _dispatch_mgr_thread$VARIANT$up + 34


My code is not involved at all, but for catching the reporting the crash. The Xcode crash report also reports:

__CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 14


I am totally in the dark about what it might be and how to solve it. Any suggestion?

Answered by fbartolom in 20621022

The crash seemed due to calling a new datatask on NSURLSession.sharedSession() before the previous one was terminated. I came to that by trial an error by trying and removing all code specific for the target.


Apple said crashes happened closer to the problem in Swift, than in Objective-c, but it seems to be returning to the time of the C dangling pointers! That is where 90's computer science and php programming experience come to the fore!


Please Apple take note Swift should be a 21 century language for the next 20 years and the runtime support should be consequent!

What sort of things did you add/convert in your code in Swift?

Accepted Answer

The crash seemed due to calling a new datatask on NSURLSession.sharedSession() before the previous one was terminated. I came to that by trial an error by trying and removing all code specific for the target.


Apple said crashes happened closer to the problem in Swift, than in Objective-c, but it seems to be returning to the time of the C dangling pointers! That is where 90's computer science and php programming experience come to the fore!


Please Apple take note Swift should be a 21 century language for the next 20 years and the runtime support should be consequent!

I think another problem is using .ReloadRevalidatingCacheData as the cache policy. I had yet another silent crash before the returing of the data.

Now I set .ReloadIgnoringLocalAndRemoteCacheData.


Thi thing is getting one of trial and error - in fact in the WWDC talked of a language lating 20 years, no of its run-time! : this is my method, anyway:


private func downloadCloseBuses(){
        /
        let localizer=referenceSingleton.sharedReferenceCounter()
        let location=localizer.referenceLocation
        let urlString="http:/
        println(urlString)
        let url=NSURL(string:urlString)!
        let urlRequest=NSURLRequest(URL: url, cachePolicy:.ReloadIgnoringLocalAndRemoteCacheData, timeoutInterval: 50)
        let request = NSURLRequest(URL: NSURL(string: urlString)!)
        let task = NSURLSession.sharedSession().dataTaskWithRequest(urlRequest, completionHandler: {[weak self] (data, response, error) -> Void in
            let datastring = NSString(data: data, encoding: NSUTF8StringEncoding)
            println("Task completed: "+(datastring! as String))
            dispatch_async(dispatch_get_main_queue(), {
                self!.timer=NSTimer.scheduledTimerWithTimeInterval(40, target: self!, selector: Selector(self!.downloadCloseBuses()), userInfo: nil, repeats: false)
            })
        })
        task.resume()
    }

Not enough, the 4th time the function is called, it crashes again bofore calling its completion handler. At least I have cornered the problem.

This is the amended class:


@objc public  class ExpressBackofficeLoader: NSObject {
    public class func sharedLoader() -> ExpressBackofficeLoader {
        struct Static {
            static let instance : ExpressBackofficeLoader = ExpressBackofficeLoader()
        }
        return Static.instance
    }
   
    override private init(){
        super.init()
        println("init called: calling download");
        downloadCloseBuses()
    }
   
    let session:NSURLSession = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
   
    private func downloadCloseBuses(){
        /
        let localizer=referenceSingleton.sharedReferenceCounter()
        let location=localizer.referenceLocation
        let urlString="http:/
        println(urlString)
        let url=NSURL(string:urlString)!
       /
        let task = session.dataTaskWithURL(url, completionHandler: {[weak self] (data, response, error) -> Void in
            println("in the closure")
            let datastring = NSString(data: data, encoding: NSUTF8StringEncoding)
            println("Task completed: "+(datastring! as String))
            dispatch_async(dispatch_get_main_queue(), {
                NSTimer.scheduledTimerWithTimeInterval(60, target: self!, selector: Selector(self!.downloadCloseBuses()), userInfo: nil, repeats: false)
            })
        })
        task.resume()
    }
}

For some reason at a certain point the timer is triggered immediately instead of after 60 seconds and at that time it crashes. All functions are private and the class is a singleton, so there is no risk some other entity might call it.

I updated the function to use GCD instead of a timer and it seems to crash no longer:

    let session:NSURLSession = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
   
    private func downloadCloseBuses(){
        /
        let localizer=referenceSingleton.sharedReferenceCounter()
        let location=localizer.referenceLocation
        let urlString="http:/
        println(urlString)
        let url=NSURL(string:urlString)!
       /
        let task = session.dataTaskWithURL(url, completionHandler: {[weak self] (data, response, error) -> Void in
            println("in the closure")
            let datastring = NSString(data: data, encoding: NSUTF8StringEncoding)
            println("Task completed: "+(datastring! as String))
            let delayTime = dispatch_time(DISPATCH_TIME_NOW,
                Int64(60 * Double(NSEC_PER_SEC)))
            dispatch_after(delayTime, dispatch_get_main_queue()) {
                self!.downloadCloseBuses()
            }
        })
        task.resume()
    }

“For some reason at a certain point the timer is triggered immediately instead of after 60 seconds”


You're calling it immediately here

NSTimer.scheduledTimerWithTimeInterval(60, target: self!, selector: Selector(self!.downloadCloseBuses()), userInfo: nil, repeats: false)

Selector should be initialised with a string (or implicitly since it is StringLiteralConvertible), not by calling a function within its initialiser. You're using this initialiser of Selector by accident

/// Create an instance initialized with `nil`.
init(nilLiteral: ())

because your function downloadCloseBuses returns nil.

Desultory crashes in my app since introducing Swift code
 
 
Q