Skip to main content
  1. Posts/

Swift Pitfalls

·396 words

I’ve started a couple experiments in iOS 8 development using Apple’s new language Swift and learned a few lessons that I want to share.

Blocks and Automatic Reference Counting (ARC) #

Swift supports blocks, or “closures”, as other languages call them. You can provide a block as handler, e.g. for an asynchronous HTTP request. This is excellent if you want to do updates in the background and a simple way to handle some updates (data and UI) when the new data has arrived.

A block in Swift will capture references that are used form the surrounding context. If you use self reference in the block, a reference to it will be retained.

You can work around this by defining the captured references as weak references, specifically one of the following types:

  • unowned: the reference is handled like a regular reference in the closure but doesn’t count towards the strong references. This is the option to use when the block is actually contained and owned by the held reference (e.g. self).
  • weak: the reference is handled as Optional and could turn to nil at any point during execution.

Captured references can be defined in a block like this:

var block = {
    [unowned self, weak otherReference] // captured references
    (parameter) in // input parameters to the block
    self.name = parameter 
}

The block will then respectively not keep a strong reference to the captured objects and allow ARC to clean up object accordingly when needed.

I have a bit of code that can issue a simple JSON-RPC request dynamically, and it was retaining references to self before I added the [unowned self] bit.

private func asyncRequest(command: String, parameters: [String], callback: ((NSData!, NSURLResponse!, NSError!) -> Void)) -> 
NSURLSessionDataTask {
    let url = NSURL(string: command, relativeToURL: baseUrl)
    var request = NSMutableURLRequest(URL: url)
    request.HTTPMethod = "POST"
    request.HTTPBody = "{\"nocache\":\(NSDate().timeIntervalSince1970),\"method\":\"\(command)\",\"params\": [\(parameters)]}".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)
    
    let task = NSURLSession.sharedSession().dataTaskWithRequest(request, callback)
    return task
}
	
// somewhere else in the code...

var task = self.asyncRequest("rpcmethod", parameters: ["1234"]) {
    [unowned self] (data, response, error) in
    self.groupCache = parse(data)
}

UITableView Updates from Dynamic Data Sources #

And another interesting thing, related to UIKit, not so much to Swift about updating UITableViews that show data from external services (e.g. via REST). This article on codeproject.com discusses a solution for Updating UITableView with dynamic data sources.

Also the apple developer documentation on Batch Update of UITableView Operations is very interesting.