Working with Reverse Ranges in Swift

Update: Xcode 6 beta 4 brought changes pertaining iterating through ranges. The content below is thus outdate. See this post.

Reverse ranges have a weird behaviour in Swift. For example:

for index in 5..<1 {
    println(index)
}

The code above results in an infinite loop. That's because the loop starts from 5 and increments at each iteration, never actually reaching 1.

In order to get the expected result of printing the numbers from 5 to 2, one should use the by() member function of the range structure, passing in -1 as the value for the step:

for index in (5..<1).by(-1) {
    println(index)
}

Note it’s necessary to enclose the range inside parentheses.

However, there’s a catch. Iterating in reverse through the open interval, built with ..<, will yield the expected behaviour, which in the example above is to print the values 5, 4, 3 and 2. However, if the closed range operator - ... - is used, instead of going until 1, the loop will stop at 3. Weird, but that’s because a...b is defined as a..<advance(b,1).

Another option to iterate through a reverse range is to use the ReverseRange() function, which will work as expected for closed ranges:

for index in ReverseRange(range:1...5) {
    println(index)
}

The code above prints 5, 4, 3, 2 and 1 as expected. However, the same code with an open range operator will print starting from 4, since the reverse of 1..<5 is actually 4...1.

Adapted from my answer on Stack Overflow

Making HTTP Requests in Swift

As I mentioned in a previous post, I've been meaning to write more about programming here. While my initial idea was to set up a separate feed, I'll just post as I normally do and think about it on another occasion.

I'll start with a series of posts on Swift, Apple's new programming language for iOS and OS X development. The first few posts will be based on some of my answers to questions on Stack Overflow. So, without further adue, let us discuss simple HTTP GET Requests in Swift.

The same options available in Objective-C can be used with Swift. I'll only cover those that don't involve using third party libraries such as AFNetworking.

Using NSURLSession

First, initialize an NSURL object and an NSURLSessionDataTask from NSURLSession. Then, run the task with resume().

let url = NSURL(string: "http://www.stackoverflow.com")

let task = NSURLSession.sharedSession().dataTaskWithURL(url) {(data, response, error) in
    println(NSString(data: data, encoding: NSUTF8StringEncoding))
}

task.resume()

Pretty straightforward. Also, the block syntax in Swift is much more pleasant to read and write, specially when benefiting from trailing blocks, which is possible since the block parameter is the last argument to the NSURLSessionDataTask initializer.

Using NSURLConnection

First, initialize an NSURL and an NSURLRequest:

let url = NSURL(string: "http://www.stackoverflow.com")
let request = NSURLRequest(URL: url)

Then, you can load the request asynchronously with:

NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()) {(response, data, error) in
    println(NSString(data: data, encoding: NSUTF8StringEncoding))
}

Or you can initialize an NSURLConnection:

let connection = NSURLConnection(request: request, delegate:someObject, startImmediately: true)

Just make sure someObject implements the NSURLConnectionDataDelegate protocol, and then deal with the data received in the appropriate delegate methods.

For more detail, check the documentation for the NSURLConnectionDataDelegate protocol

Testing on an Xcode playground

In order to try this on an Xcode playground, add import XCPlayground to your playground, as well as the following call:

XCPSetExecutionShouldContinueIndefinitely()

This will allow you to use asynchronous code in playgrounds.

Final remarks

While I provided code that uses both NSURLSession and NSURLConnection, NSURLSession is the preferred solution. Even though NSURLConnection isn't officially deprecated, this has been stated by Apple engineers on several occasions during WWDC sessions.

Finally, here's a gist with the NSURLSession based implementation.

Adapted from my answer on Stack Overflow