List Comprehensions and Performance With Swift

This post written on August 15, 2015 to be compatible with Xcode 6 and Swift 1.2

List comprehensions provide a concise way to create lists. You can accomplish list comprehension-like operations in Swift even though list comprehensions are not mentioned in the Swift language guide.

Say you want to create a list of squares, like:

var squares = [Int]()
for x in 1..<10 {
    squares.append(x*x)
}

In Python you could use a list comprehension instead

squares = [x**2 for x in range(10)]

In Swift you can do

let squares = Array(map(1..<10) { $0 * $0 })

To get the sum of all the elements in the list you could do this

var sum = 0
for square in squares {
    sum = sum + square
}

Or use the reduce function

let sum = squares.reduce(0, { $0 + $1 })

Like list comprehensions in some other languages, you can use any Sequence or Collection as the input, not just a Range.

You can use map/reduce/filter/stride depending on what kind of list you are trying to create.

The two main perks of list comprehensions are conciseness and being able to generate faster bitcode.

My imitation list comprehension was more concise. I was curious whether it would also generate faster bitcode.

This article showed me how to analyze Swift assembly code using Hopper, an OSX and Linux disassembler. You can try Hopper for free without buying a license.

The code snippets without list comprehensions and with the imitation list comprehensions generated the same assembly code.

The assembly code from Hopper

Since both snippets created the same assembly code I assumed their execution time would be the same. We can demontrate this by measuring the execution of our program using XCTest.

My test for the code snippet with no list comprehension

func testNoListComprehensionPerformance() {
    self.measureBlock() {
        var squares = [Int]()
        for x in 1...5 {
            squares.append(x)
        }
    }
}

The relevant output

Test Case '-[speedTestTests.speedTestTests testNoListComprehensionPerformance]' started.

:0: Test Case '-[speedTestTests.speedTestTests testNoListComprehensionPerformance]' measured [Time, seconds] average: 0.000, relative standard deviation: 236.965%, values: [0.000154, 0.000005, 0.000004, 0.000004, 0.000004, 0.000004, 0.000004, 0.000004, 0.000004, 0.000004], performanceMetricID:com.apple.XCTPerformanceMetric_WallClockTime, baselineName: "", baselineAverage: , maxPercentRegression: 10.000%, maxPercentRelativeStandardDeviation: 10.000%, maxRegression: 0.100, maxStandardDeviation: 0.100
Test Case '-[speedTestTests.speedTestTests testNoListComprehensionPerformance]' passed (0.262 seconds).

My test for the code snippet with the imitation list comprehension

Test Case '-[speedTestTests.speedTestTests testSortaListComprehensionPerformance]' started.

:0: Test Case '-[speedTestTests.speedTestTests testSortaListComprehensionPerformance]' measured [Time, seconds] average: 0.000, relative standard deviation: 160.077%, values: [0.000045, 0.000005, 0.000004, 0.000003, 0.000003, 0.000003, 0.000003, 0.000004, 0.000003, 0.000003], performanceMetricID:com.apple.XCTPerformanceMetric_WallClockTime, baselineName: "", baselineAverage: , maxPercentRegression: 10.000%, maxPercentRelativeStandardDeviation: 10.000%, maxRegression: 0.100, maxStandardDeviation: 0.100
Test Case '-[speedTestTests.speedTestTests testSortaListComprehensionPerformance]' passed (0.255 seconds).

On average they only differ by only 0.007 seconds.

The coolest application of list comprehensions I've seen is in a spelling corrector. Airspeed Velocity wrote a Swift version of Peter Norvig's Python spelling corrector.

Conciseness is the main benefit of using list comprehension-like operations in Swift. Paul Graham wrote a great essay about how conciseness in programming languages is power. Since each programmer can only write a certain number of lines of code per day, you can accomplish more each day if you can accomplish more in the same number of lines. This power also makes you rethink what programs are possible. In a more verbose language this spelling corrector example could have seemed like an overwhelming project. I love how how something as technically complex and mysterious as a spelling corrector can be expressed in so few lines of code in Swift.


Sign up now and get a set of FREE video tutorials on writing iOS apps coming soon.



Subscribe via RSS

Swift 2 – What’s new

Monday Apple announced Swift 2, and just about everything announced is an extremely welcome change. This post is a summary of Chris Lattner’s discussion in the WWDC video “What’s new in Swift”. Now, let’s run through them…

Fundamentals

enums can now be printed to the console and show the actually value instead of just (enum value). Additionally, println is now just print. If you have ever used log debugging to figure out a problem involving enum values, rejoice!

I tested this and saw that not only is the enum value is printed, but so is the entire context of when and where the print() function is called.

enums can now support multiple types, so long to Box!

enum<T1, T2> {
  case First(T1)
  case Second(T2)
}

The do keyword:

do {
  //...
} while(someVar<5)

// Can now be represented as:
repeat {
  //...
}

Option Sets can now use a standard Set type in Swift 2.0

viewOptions = .Repeat | .CurveEaseIn
viewOptions = nil

// Can now be represented as a set:

viewOptions = [.Repeat, .CurveEaseIn]
viewOptions = []

We can also create our own set types

(Default implementations in protocols)

struct MyStyle : OptionSetType {
  let rawValue: Int
  static let Bold     = MyStyle(rawValue: 1)
  static let Italic   = MyStyle(rawValue: 2)
}

iStyle.style = []
iStyle.style = [.Bold, .Italic]

if iStyle.style.contains(.Bold) {
  //...
}

Function arguments now behave the same way, regardless of if they are global functions, or methods on a data structure.

So now, you provide arguments labels on functions by default:

func myFunc(name: String, age: Int) { ... }

myFunc("John", age: 35)

The # syntax is now gone, previously used to make the external argument name the same as the internal argument name.

In tests, public and internal are visible, via running a special run mode.

Pattern Matching
Added the guard statement which exits the scope in the else statement.

guard let name = json["name"] as? String else {
  return .Second("missing name")
}

// You can also combine this is to complex guards
guard let name = json["name"] as? String,
      let year = json["year"] as? Int else
    return .Second("bad input")
}
// name and year are now String and Int types, not optionals!
return .First(name, year)

Switch/case can now be used with inline if statements

switch bar() {
case .SomeCase(let value) where value != 42:
  doThing(value)

default: break
}

// Can now be represented as
if case .SomeCase(let value) = bar() where value != 42 {
  doSomething(value)
}

for in loops now support boolean filters and full pattern matching

for value in mySequence where value != "" {
  doThing(value)
}

for case .MyEnumCase(let value) in enumValues {
  doThing(value)
}

BONUS: Example of try-catch for JSON vs invalid JSON

let jsonString = "{\"name\":\"Fred\", \"age\":40}"
let badJsonString = "This really isn't valid JSON at all"

let jsonData = jsonString.dataUsingEncoding(NSUTF8StringEncoding)!
let badJsonData = badJsonString.dataUsingEncoding(NSUTF8StringEncoding)!

do {
    // Try parsing some valid JSON
    let parsed = try NSJSONSerialization.JSONObjectWithData(jsonData, options: NSJSONReadingOptions.AllowFragments)
    print(parsed)
    
    // Try parsing some invalid JSON
    let otherParsed = try NSJSONSerialization.JSONObjectWithData(badJsonData, options: NSJSONReadingOptions.AllowFragments)
    print(otherParsed)
}
catch let error as NSError {
    // Catch fires here, with an NSErrro being thrown from the JSONObjectWithData method
    print("A JSON parsing error occurred, here are the details:\n \(error)")
}


Sign up now and get a set of FREE video tutorials on writing iOS apps coming soon.



Subscribe via RSS

Open Source Swift – A Look At The Top Swift Repositories

Github, the most popular open source repository for open source software, offers a feature that let’s us view repositories by language. In this post, I want to dissect some of the most popular Swift repositories as of June 5th, 2015. So, let’s kick it off with the most starred Swift repository, Alamofire.

Alamofire

Alamofire is an “Elegant HTTP Networking in Swift”, written by Matt Thompson, a well known Objective-C developer responsible for the AFNetworking library. The library takes the built-in iOS networking features and abstracts them away in to a simpler, and more Swift-y API.

Take for example the case of a simple GET request that returns JSON:

Alamofire.request(.GET, "http://httpbin.org/get")
         .responseString { (_, _, string, _) in
                  println(string)
         }

It’s the most popular library for Swift to date, so you should probably be using it, right?

Well, maybe… The library makes some common tasks simpler and less verbose, but if you don’t know the basics of networking in Swift (or Objective-C), it’s probably best to get a good understanding of the existing APIs first. After understanding what’s going on under the hood, you can make a more informed decision about whether or not you need the extra layer of abstraction. Alamofire is a big framework, and networking is a huge topic, so I don’t want to get too far in to the details on this library. But, suffice to say if you are working with complex networking requests with lots of back and forth with a web server, and/or working with a complicated authentication process, using Alamofire might reduce some of the repetitive coding tasks. If you are new to iOS development, I would recommend just stick to the APIs provided by Apple for now.

SwiftyJSON

SwiftyJSON is “The better way to deal with JSON data in Swift” according to it’s Github entry. This framework is one of the first I saw when Swift was first released, that combined with the fact that JSON parsing is such a common problem is how it became a top repository, helping to deal with the messiness of Apple’s built-in JSON parser. In particular, the static typing of Swift and optional syntax led to a lot of verbose JSON parsing code, guessing and checking each step of the way for each key and checking every cast. The truth is though, using this library is VERY similar to just using optional chaining and Swift’s normal casting syntax. There is not much benefit here, and from what I’ve seen in production, SwiftyJSON has some performance problems, as a result I’m not sure I would recommend using it right now, except in prototype apps, or during the learning phase.

Take a look at the example they give as the standard approach to parsing JSON, which they describe as “not good”:

let JSONObject: AnyObject? = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: nil)

if let statusesArray = JSONObject as? [AnyObject],
   let status = statusesArray[0] as? [String: AnyObject],
   let user = status["user"] as? [String: AnyObject],
   let username = user["name"] as? String {
    // Finally we got the username
}

They then present their alternative version of the syntax:

let json = JSON(data: dataFromNetworking)
if let userName = json[0]["user"]["name"].string{
  //Now you got your value
}

There’s a few issues here, first of which is that the simplifications they are showing are partially just taking advantage of language features that would actually work with the regular parser. Second, it seems like their example actually would not work.

Based on the example code shown above, the example JSON they are parsing looks something like this:

{
    "statuses": [
        {
            "user": {
                "name": "Bob"
            }
        }
    ]
}

One issue with this sample right off the bat is that they are casting the initial value of the JSON to an array, which would suggest that the root element is an array, which is invalid JSON. The type of the root object in valid JSON is always going to be a key/value. Or equivalently in Swift, a Dictionary of type [String:AnyObject]. Additionally, it’s good practice to actually check if the JSON parsing succeeded or not.

Once we start going through and fixing all the issues with the sample code, assuming we want to explicitly cast everything as they have shown, we end up with something like this:

if let JSONObject = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: nil) as? [String:AnyObject],
    statusesArray = JSONObject["statuses"] as? [[String:AnyObject]] {
        let status = statusesArray[0] as [String: AnyObject]
        if let user = status["user"] as? [String: AnyObject],
            let username = user["name"] as? String {
                println("username: \(username)")
        }
}
else {
    println("Failed to parse JSON, handle this problem")
}

Now, this is in fact pretty verbose, and could be reduced quite a bit, but let’s stop a think about what we’re doing here. In this example, we are trying to download a list of statuses which are owned by users, and they have names. In an actual Swift application, I would expect there to be a model representing these objects. Maybe something like this:

struct User {
    let name: String
}
struct Status {
    let user: User
}

Assume we are using SwiftyJSON for a moment, how would we add these records to the model of our app? Maybe with a bit of code like this…

struct User {
    let name: String
}
struct Status {
    let user: User
}

let parsedJson = JSON(data: data)
for (key, val) in parsedJson["statuses"] {
    if let username = val["user"]["name"].string {
        let owner = User(name: username)
        let newStatus = Status(user: owner)
    }
}

This works relatively well, assuming we are just creating objects from a JSON feed rather than synchronizing them. But what if there is a server error and the JSON comes back invalid? For example if there is a server error which changes the JSON to present an “error” key, and it no longer includes “statuses”, this loop simply would not be executed. Failing silently is better than crashing, but it would be nice to check for issues and try again, or adjust something in the app.

Since we need to check for the presence of statuses, and this for loop doesn’t actually do that, we need to check the count of statuses first, which means we need to cast it to an array, and *then* check the count…

if(parsedJson["statuses"].count<1) {
    println("Oops! An error occurred")
}

And that's that! Right?
Well, no...

If the key isn't defined, this count property evaluates to 0, which could just mean there is no new statuses to see. The count really should not be zero, it should be null.. but SwiftyJSON is telling us it's 0. This seems like the kind of thing I really *don't* want a JSON parser to be doing. They really seem to not like the optional syntax in Swift, and instead reinvented it with these type properties. Why not just stick with convention?
Our final code might look something like this:

struct User {
    let name: String
}
struct Status {
    let user: User
}

let parsedJson = JSON(data: data)
for (key, val) in parsedJson["statuses"] {
    if let username = val["user"]["name"].string {
        let owner = User(name: username)
        let newStatus = Status(user: owner)
    }
}
if(parsedJson["statuses"].count<1) {
    println("Oops! An error occurred")
}
if let err = parsedJson["error"].string {
    println(err)
}

Our code is starting to grow, and this doesn't cover a ton of things we would need in a real-world application, such as updating the model, including more properties, checking for equality, enforcing uniqueness, cascading relationship changes, and a host of other things. Core Data can handle much of this, and it's common practice to implement models as Core Data models, but that still creates a situation where we have to custom implement all kinds of methods for converting the entire model object (such as Status) *back* in to JSON to update the server.

In the Objective-C world there is Mantle, a great library for handling such things. Before that there was RestKit. RestKit however made some ...interesting... design decisions a few years ago in a big update, and haven't ever really recovered since then. Unfortunately I haven't found a good solution for Swift just yet, and trying to work with Mantle proves to be problematic in it's current form, unless you implement all your models in Obj-C, something I'm not sure we all want to do at this stage.

I know this isn't all problems with SwiftyJSON, but they ironically break a lot of Swift conventions in dealing with optional values. SwiftyJSON is really a terrible name, they are very much not Swifty at all. However, the syntax is a little easier on the eyes. Personally, I don't use the library in my projects.

Spring

Spring is "A library to simplify iOS animations in Swift." How does it do this? Let's take a look.

Trying out some sample code I threw together this quick demo UIViewController that adds a blue square to the screen and animates it in, give it a try yourself, it's pretty nifty:

import UIKit
import Spring

class ViewController: UIViewController {
    var square = SpringView(frame: CGRectMake(0, 0, 200, 200))
    override func viewDidLoad() {
        super.viewDidLoad()
        
        square.center = self.view.center
        square.backgroundColor = UIColor.blueColor()
        square.animation = "squeezeDown"
        square.animate()

        self.view.addSubview(square)
    }
}

The SpringView seems to basically just be a UIView subclass with the animations added in. I don't know if I really like the idea of having to use their UIView, but I suppose most of the time I just use the basic UIView, and even if I didn't, I could just subclass SpringView instead.

Spring sports quite a few animation types, set as a string. The square.animation = "squeezeDown" here is what's determining the animation to play. The library goes beyond this, and in fact allows simple animations to be created in storyboards. So in theory you could put Spring in your Xcode project, and then pass it off to a designer to set up some nifty animations using this library. Very interesting idea, I would like to hear from someone who has tried to do exactly this.

Quick

Quick is "The Swift (and Objective-C) testing framework."

Really? It's THE testing framework? Let's take a look at how Quick works as opposed to XCTest, or expecta.

In XCTest, you might define an assertion that you're testing against like this:

class JSONSwiftTests: XCTestCase {
    
    override func setUp() {
        super.setUp()
        // Put setup code here. This method is called before the invocation of each test method in the class.
    }
    
    override func tearDown() {
        // Put teardown code here. This method is called after the invocation of each test method in the class.
        super.tearDown()
    }
    
    func testContrivedExample() {
        let name = "jameson"
        XCTAssertEqual(name, "jameson", "Name should be \"jameson\"")
    }
}

This is okay, it makes the test basically confirm that name is equal to "jameson". It's simple enough, but there is a common trend/desire among developers to instead express test cases in terms of desired behavior, rather than specifically implementing what the desired behavior causes. Those may sound like the same thing, but take a look at how Quick (due to it's usage of the library Nimble) expresses the same thing like this:

import Quick
import Nimble

class AQuickTest: QuickSpec {
    override func spec() {
        describe("the user") {
            it("has the name 'Jameson'") {
                let name = "Jameson"
                expect(name).to(equal("Jameson"))
            }
        }
    }
}

More than anything else, this framework encourages behavioral tests, which is why this example includes more information about our expectations.

Quick also eases some of the pain of asynchronous testing. In XCTest I personally tend to use XCTestAsync, although Xcode 6 does introduce a way to do this using XCTestExpectation. The basic way that works is you can create an expectation object, and then fulfill it when the async operation is complete. It's not a bad approach.

import Quick
import Nimble

@objc class AsyncExample {
    var longTaskIsDone = false
    var timer: NSTimer?
    func startLongTask() {
        timer = NSTimer.scheduledTimerWithTimeInterval(2, target: self, selector: "taskIsDone", userInfo: nil, repeats: false)
    }
    func taskIsDone() {
        println("task done")
        longTaskIsDone = true
    }
}

class AQuickTest: QuickSpec {
    override func spec() {
        describe("the user") {
            it("has the name 'Jameson'") {
                let name = "Jameson"
                expect(name).to(equal("Jameson"))
            }
        }
        
        describe("Async Example") {
            describe("its long task") {
                it("should finish in 5 seconds") {
                    let asyncExample = AsyncExample()
                    asyncExample.startLongTask()
                    expect(asyncExample.longTaskIsDone).toEventually(beTruthy(), timeout: 3, pollInterval: 0.4)
                }
            }
        }
        
    }
}

In this example we just create an NSTimer that fires in 2 seconds, as a simulated async example. Then in the Async Example test, we can use the .toEventually() method to wait around and keep checking in to the asyncExample.longTaskIsDone property. This is slightly cleaner in that using expectations, because with this method we don't need to change our code to make sure the test is notified of this variable changing. Having an ongoing timer keep checking is great (just be careful not to have it calling methods with side effects!)

Overall Quick seems pretty interesting, the approach is sure to appeal to those in professional environments, or working with an Agile team where specs change fast.

That's it for this time, if you would like to see any of these libraries covered in greater detail be sure to let me know. You can find me on Twitter.


Sign up now and get a set of FREE video tutorials on writing iOS apps coming soon.



Subscribe via RSS

Function Currying in Swift

Function Currying in Swift

The concept of currying is that instead of accepting multiple arguments, a function accepts only one, and returns a function which acepts the remaining arguments. The returned function will also accept only one argument, and returns another function. This process continues until all arguments are exhausted and we are left only with a single return value.

For example, usually we define a function that returns the sum of two integers as follows:

func add1(x: Int, y: Int) -> Int {
    return x + y
}
add1(1, 2) // Output: 3

We can always transform a function taking multiple arguments into a curried one, by separating the function into a series of function that each takes only one argument. The curried version of add1 is as follows:

func add2(x: Int) -> (Int -> Int) {
    return { y in return x + y }
}
add2(1)(2) // Output: 3

This function has this type specified: Int -> Int -> Int. This may seem a little strange to newcomers to functional programming. Which part is the argument, and which part is the return type?

Here, add2 is taking an Int, and returning a Function which takes another Int, which in turn returns a third Int. You could say it’s something like this: Int -> (Int -> Int), or we could use typealias to make (Int -> Int) more clear:

typealias IntTransformer = (Int -> Int)

Now, any time we see IntTransformer, it’s easier to comprehend that it’s a function that transforms an Int value. With that, we could redfine add2 like this:

func add2Aliased(x: Int) -> IntTransformer {
...

This probably looks a little more familiar, but under the hood this is exactly the same as the add2 function we defined with the data type Int -> Int -> Int. This is just a more familiar looking way to write it.

Calling add2() with just a single argument returns a function that takes another (Int -> Int) function, which means we can store that function in a separate variable if we so choose:

let addTwentyTransformer = add2(20)
addTwentyTransformer(5) // Output: 25

Now, add2(20) is a function that takes one integer and returns the value of that integer plus 20.

The -> operator is defined as associativity right. Instead of writing A -> (B -> (C -> D)), we can simply write A -> B -> C -> D.

Swift also supports another way to define a curried function:

func add3(x: Int)(y: Int) -> Int {
    return x + y
}
add3(1)(y: 2) // Output: 3

This is helpful if you want named parameters, which can sometimes help your code easier to read. It’s also easy to make the syntax the same as add2 and remove the explicit argument name.

func add4(x: Int)(_ y: Int) -> Int {
    return x + y
}
add4(1)(2) // Output: 3

Benefits of Currying

What are the benefits currying provides? Let’s look at the add functions above.

With add1 the regular function, we cannot apply this function until both of its arguments are ready. With the curried add2, we can apply one or two arguments.

Let’s see an example that uses add1 and add2 with mapto transform an array of integers by adding 7 to each.

// Apply map to the array using the two functions
let xs = [1, 2, 3]
let addSeven1 = { add1($0, 7) }
map(xs, addSeven1) // Output: [8, 9, 10]
let addSeven2 = add2(7)
map(xs, addSeven2) // Output: [8, 9, 10]

The curried function add2 is much cleaner in this case.

There is another case when curried functions have obvious advantages. To demonstrate the example, first we define a function (a custom operator) that composes two functions together:

// Define a new operator |> that has left associativity
infix operator |> { associativity left }
func |> <A, B, C>(f: B -> C, g: A -> B) -> A -> C {
    return { x in
        f(g(x))
    }
}

Let’s say we want to transform an array of integers by adding 7 to each element, and then adding 3 again. We could write:

let xs = [1, 2, 3]
 
// Returns a function that adds three to it's only argument
let addThree = add2(3)
 
// Apply addSeven1 to every item in xs
// Then apply addThree to every item in that list
xs.map(addSeven1).map(addThree) // Output: [11, 12, 13]

It first adds 7 to each element in xs, wraps the results into a temporary array, then add 3 to each in the temporary array, and return the last results in a new array. This creates a temporary array that we never need.

By composing the curried functions, addSeven2 and addThree, we can eliminate the creation of the temporary array.

xs.map(addSeven1 |> addThree) // Output: [11, 12, 13]

Builtin Currying Functions in Swift

In the Swift standard library there is a function on the Int type called advancedBy that takes an amount, and returns an Int that has been adjusted by that amount.

extension Int : RandomAccessIndexType {
    func advancedBy(amount: Distance) -> Int
}

It’s simple enough to use this function on an Int and get the advanced value:

5.advancedBy(6) // Output: 11

But because of function currying, we could get the partial application of this function by not specifying the initial value to be advanced:

let add6 = Int.advancedBy(6)
add6(5) // Output: 11
add6(10) // Output: 10

Let’s look at the following example. To insert another string at the end of the given string, we could call the splice function on an instance of String:

var s = "Hello"
s.splice(", world", atIndex: s.endIndex)
// Output: "Hello, world"

Or we can call it on String data type, and pass the String instance as its only argument:

String.splice(&s)("!!!", atIndex: s.endIndex)
s // Output: "Hello, world!!!"

The splice function on a String instance is not a curried function. s.splice("!!!")(atIndex: s.endIndex) will not compile.

The term partial application, is a function that accepts only some of its arguments, and returns another function that takes the rest of arguments. While a curried function takes only one argument.

Don’t confuse partial application with another term called partial function. Partial function is a function that cannot provide a valid result for all its possible inputs. In Objective-C, if we call [[NSString alloc] initWithString:nil], it will compile but throw a NSInvalidArgumentException at runtime. -initWithString: is a partial function, because there is no return value for nil.

Next Steps

Is this all making sense? This can all be quite a chunk of new information to take in if you are new to functional programming in general. For that reason we are preparing a free functional programming course that is in private beta testing right now. If you want to be part of the beta, or just want us to let you know when it’s ready, sign up for the beta here.


Sign up now and get a set of FREE video tutorials on writing iOS apps coming soon.



Subscribe via RSS

Functional Programming in Swift

Thoughts on Functional Programming in Swift

Like most of you, I have to use Objective-C at my day job. I could only craft my Swift skills at night. Swift is not a purely functional language. It can be use imperatively because all frameworks from Apple are written in Objective-C at the time of writing. However, it is also functional, learning from modern languages like Haskell, F#, etc. At the beginning when reading Swift blogs and tutorials, many people talked about terms like functors and monads, those sounded alien-like to me. I started to learn Haskell to understand what they were talking about. I’m not an expert, and still learning functional programming and Swift, but I wanted to share what I’ve learned so far. Hopefully it will save you some troubles to get into the functional programming world.

Key Concepts

Higher-order functions

One key concept of functional programming is higher-order functions. According to Wikipedia, a higher-order function:

  • takes one or more functions as an input
  • outputs a function

In Swift, functions are first-class citizens, like structs and classes, as we can see in the following example:

let addFive = { $0 + 5 }
addFive(7) // Output: 12

We define a function as an inline closure, and then assign it to an inline closure. Swift provides shorthand argument to it. Instead of by name, we can refer to the arguments by number, $0, $1 and so on.

func addThreeAfter(f: Int -> Int) -> Int -> Int {
    return { f($0) + 3 }
}
let addEight = addThreeAfter(addFive)
addEight(7) // Output: 15

The argument type Int -> Int means it is a function that takes an Int as an argument, and returns an Int. If a function requires more than one arguments, for example, it has two Int argument, we can define the type as (Int, Int) -> Int.

The return type of addThreeAfter is also a function. It equivalents to func addThreeAfter(f: Int -> Int) -> (Int -> Int).

[addFive, addEight].map { $0(7) } // Output: [12 15]

map is a special function for container type, such as Array, Optional. It unwraps values from the container type, then applies a transform for each, and wraps them again. We use map here to pass 7 as an argument to each function in the array, and wraps the results into a new array.

In summary, we can assign functions to variables, store them in data structures, pass them as arguments to other functions, and even return them as the values from other functions.

Pure functions

A function is called a pure function if it has no observable side effects. But what the heck is side effect?

A function or expression is said to have a side effect if, in addition to returning a value, it also modifies some state or has an observable interaction with calling functions or the outside world.
— from Wikipedia

The two functions addFive and addEight are pure functions. They don’t modify the input value, or change any global state. In the example below, addFive2 modifies the input, so it is not a pure function.

func addFive2(inout a: Int) -> Int {
    a += 5
    return a
}
var a = 7
addFive2(&a)
a // Output: 12

Functions that access or modify a database, the local file system, or printing strings to the screen are also considered impure. Because they modify the state of the database records, file system, and display buffers respectively. Sometimes side effects are desirable. Without side effects, we could not interact with the program.

Haskell introduces types like IO to separate pure and impure layers. But in Swift, we don’t need to worry too much about this separation. We could still use Cocoa APIs as usual. But, I strongly encourage the use of pure functions whenever possible. With pure functions, the code is more predictable. A pure function will always return the same value if given the same input. It’s easy to test, too. We don’t need to mock a data structure to satisfy its internal state requirements to test a function.

Imperative & Functional Programming

All above are very theoretical. You may want to know how functional programming with help us solve problems in a better, clearer, or less error-prone way. What are the benefits we could gain from it?

First, you need to understand that we could do almost anything in imperative programming, and functional programming does not extend the possibilities of what we could do.

Second, if you come from the imperative programming world, some functional code is harder to understand at first, especially those with custom operators. It is not because functional programming is hard and obscure, but it’s because our mindsets are trained from years of imperative programming practices.

Take a look at this example of imperative code, which we can rewrite as functional code. These two do exactly the same things.

// Imperative
var source = [1, 3, 5, 7, 9]
var result = [Int]()
for i in source {
    let timesTwo = i * 2
    if timesTwo > 5 && timesTwo < 15 {
        result.append(timesTwo)
    }
}
result // Output: [6, 10, 14]
// Functional
let result2 = source.map { $0 * 2 }
                    .filter { $0 > 5 && $0 < 15 }
result2 // Output: [6, 10, 14]

It is arguable which one is clearer. But from this simple example you can see the main difference between imperative and functional programming. In imperative programming, we instruct the computer how to do something:

  1. Iterate through source
  2. Get the result from the element, and multiply by 2
  3. Compare it with 5 and 15
  4. If it is bigger than 5 and less than 15, put it into result

However, in functional programming, we describe what to do:

  1. Transform each element in source to itself multiplied by 2
  2. Only select the ones with value bigger than 5 and less than 15

I’m not going to persuade you functional programming is better. It’s your personal preference. After all, good code is all about writing code that:

  1. Works as intended
  2. Is clear to you and your team

An Example: Reverse Polish Notation Calculator

I like Swift and functional programming, because it enables me to solve a problem in a different perspective. There is usually more than one way to solve a problem. Exploring a better solution helps us grow to become good developers.

Let me show you a functional example. It is a calculator for algebraic expressions of reverse polish notation, or RPN in short. (It is a Swift implementation of the Haskell example in Learn You a Haskell for Great Good.)

A RPN expression of (3 + 5) 2 is 3 5 + 2 . You may think of this as a stack of numbers. We go through the RPN expression from left to right. When encountering a number, we push it onto the stack. When we encounter an operator, we pop two numbers from the stack, use the operator with those two numbers, and then push the result back onto the stack. When reaching the end of the expression, the only one number left on the stack is the result (assuming the RPN expression is valid). For more explanation about RPN, please check on Wikipedia.

We want a function that returns the result for an RPN expression.

func solveRPN(expression: String) -> Double {
    // Process the expression and return the result
}

Given a RPN expression String “3 5 + 2 *”, first we need to transform it into an array of elements that we can process. There are two kind of elements, operand and operator. The Enum data type in Swift comes in handy for defining the element. We name it RPNElement.

enum RPNElement {
    case Operand(Double)
    case Operator(String, (Double, Double) -> Double)
}

Next, we split the expression into an array of Strings, then map it into an RPNElement array.

extension String {
    func toRPNElement() -> RPNElement {
        switch self {
        case "*": return .Operator(self, { $0 * $1 })
        case "+": return .Operator(self, { $0 + $1 })
        case "-": return .Operator(self, { $0 - $1 })
        default: return .Operand(Double(self.toInt()!))
        }
    }
}
func stringToRPNElement(s: String) -> RPNElement {
    return s.toRPNElement()
}
func solveRPN(expression: String) -> Double {
    let elements = expression.componentsSeparatedByString(" ").map(stringToRPNElement)
        // Further process
}

Next, we will go through the array and process it according to how RPN works, as I described earlier. We reduce the array into a Double array. Assuming the expression is valid, the Double array should only contain one element. It will be the result we want.

func solveRPN(expression: String) -> Double {
    let elements = expression.componentsSeparatedByString(" ").map(stringToRPNElement)
    let results = elements.reduce([]) { (acc: [Double], e: RPNElement) -> [Doublein
        switch e {
        case .Operand(let operand):
            return [operand] + acc
        case .Operator(let op, let f):
            let r = f(acc[0], acc[1])
            return [r] + acc[2..<acc.count]
        }
    }
    return results.first ?? 0
}
solveRPN("3 5 + 2 *") // Output: 16

Where to Go From Here?

If you are interested in learning more about functional programming, I highly recommend the following two books:

Even though the second book is written for Haskell, but the concepts also apply to Optional in Swift as well. Besides, it explains Functor, Applicative, Monad in details.


Sign up now and get a set of FREE video tutorials on writing iOS apps coming soon.



Subscribe via RSS

Local Notifications in iOS 10 with Swift (Part 1)

This post has been updated for compatibility with XCode 8 and iOS 10

Local notifications are a simple way to display information to your user even when your app is in the background. They allow you to display an alert, play a sound or badge your app’s icon. Local notifications can be triggered at a scheduled time or when your user enters or leaves a geographical area. In this tutorial, we’ll create a simple to-do list application and delve into a number of UILocalNotification features and quirks.

First, let’s create a new single view application in Xcode and call it LocalNotificationsTutorial. Remember to choose Swift as the language.

Screen Shot 2015-01-30 at 10.15.42 PM

Before we delve into writing any code, let’s get our view controllers and views set up. This is a necessary step, and I’ll be covering some of the basics of using Interface Builder, but if want to skip it and jump right into dealing with scheduling notifications you can follow along by getting the configured application from here.

Configuring the Views

Our finished application will have two views in a navigation controller: a root view that displays a chronologically ordered list of to-do items with deadlines, and a view for creating to-do list items.

Want to just get my Swift 3 template?
Buy the completed code with examples and copy directly in to your Xcode project.
Get The Template

 

iOS Simulator Screen Shot Feb 1, 2015, 11.43.36 PM iOS Simulator Screen Shot Feb 4, 2015, 10.26.58 PM

Creating the View Controllers

Before opening Interface Builder, we should generate view controllers to back each of our views. Ctrl or right-click on the project group in the project navigator and select “New File”.

Screen Shot 2015-01-30 at 10.29.29 PM

Select “Cocoa Touch Class” from the “iOS -> Source” menu and create a subclass of UITableViewController named “TodoTableViewController”. Don’t create a XIB file, and, of course, the language should be Swift. This will be our root view controller and it will be in charge of displaying the to-do list.

We need a separate view for creating our to-do items. Repeat the process, this time create a UIViewController subclass and name it “TodoSchedulingViewController”.

Setting up Navigation

Now that our view controllers are created, let’s hook them into our project’s storyboard. Click “Main.storyboard” and delete the root view controller. Go ahead and delete “ViewController.swift” as well. We won’t be using it.

Drag a new navigation controller from the object library onto the now blank storyboard. We’ve deleted our root view, so drag a Storyboard Entry Point onto the navigation controller so our application will have a root view.

Screen Shot 2015-01-30 at 11.11.26 PM

The object library

Select the navigation controller’s root view (a table view) and set its custom class to “TodoTableViewController” in the identity inspector.

Screen Shot 2015-01-30 at 11.22.17 PM

The identity inspector

Since we’re going to display deadlines for each to-do item, we need to select the table view’s first (and only) prototype cell, switch to the attributes inspector, and set the cell’s style to “Subtitle”.  It needs a reuse identifier as well, so we can refer to it in our code. We’ll use “todoCell”.

Screen Shot 2015-01-30 at 11.39.00 PM

The attributes inspector

Keep the attributes inspector selected. Drag a navigation item onto the table view and give it the title “Todo List”, then drag a bar button item onto that and set the identifier to “Add”.

Now we’ll set up the view on which users can schedule and title their to-do items. Drag a view controller into the storyboard. Its custom class should be set to “TodoSchedulingViewController”.

Ctrl or right-click on the “Add” button, drag from the “action” to the new view, and select “show”. Now all our navigation is linked up.

Screen Shot 2015-01-31 at 12.03.33 AM

We need to drag three controls onto this view: a text field (with “Title” as the placeholder text), a date picker and a button (titled “Save”). Just center and widen all three, then “add missing constraints” to all views in the view controller (Under “Resolve Auto Layout Issues”, the triangle icon towards the bottom right of Xcode). Adding constraints ensures that the view is laid out predictably across various screen sizes (instead of having portions of controls cut off or misaligned).

Screen Shot 2015-01-31 at 12.25.08 AM

Connecting Controls to Code

Now that our views and navigation are laid out, we have to link our text field and date picker controls to an IBOutlet in TodoSchedulingViewController.swift. This will allow us to access these controls (and their values) in our code. There are a few ways to do this, but the simplest is to enable the Assistant editor by clicking the interlocking circles in the top right of XCode, Ctrl or right-click the control, and drag the “New Referencing Outlet” circle into the TodoSchedulingViewController class body.

Screen Shot 2015-01-31 at 12.45.14 AM

Do this for both the text field and the date picker, naming them “titleField” and “deadlinePicker” respectively.

@IBOutlet weak var titleField: UITextField!
@IBOutlet weak var deadlinePicker: UIDatePicker!

The final step is to connect the save button to an IBAction (an event handler function). Just Ctrl or right-click the button, and drag from the “Touch Up Inside” circle to the code window. Name the action “savePressed” and optionally set the sender type to UIButton (no other controls will be firing this action, so we can be more specific).

@IBAction func savePressed(_ sender: UIButton) {
}

The views and navigation for this project are all set up. Go ahead and run the app in the simulator. Try it for a few different devices. You’ll notice that, because of the constraints we added, your views stretch or squeeze to fit the various screen sizes.

Now, let’s get out of Interface Builder and write some code.

Registering Notification Settings

We need to register our intent to use notifications with the application. Otherwise, the notifications we schedule simply won’t fire. Switch over to your Application Delegate (AppDelegate.swift) and add the following line to application:didFinishLaunchingWithOptions:

application.registerUserNotificationSettings(UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil))

On the first launch of the app, users will now be prompted to allow your app to send notifications. If the user grants permission, we will be able to schedule notifications that display a banner, play a sound, and update our app icon’s badge number (which we’ll cover in part 2).

iOS Simulator Screen Shot Feb 3, 2015, 2.56.37 PM

Modeling the Application

For a simple app like this, it may be tempting to handle all of the logic in the view controllers that we just created, but we’ll have an easier time understanding and maintaining our code if we keep the management of the to-do list and the presentation logic separate.

I chose to model individual to-do items with a lightweight struct. Let’s create that now. Just click “File -> New -> File”, choose “Swift File” and name it “TodoItem”. Each to-do list item has a title and a deadline, so we’ll create properties for both.

struct TodoItem {
  var title: String
  var deadline: Date
}

Ultimately, each to-do list item needs to be backed by an on disk representation, so that the list will persist if the application is terminated. Instances of UILocalNotification have a userInfo property – a dictionary that we can use to store miscellaneous data like the title, but we can’t rely on that alone in this case. Local notifications are automatically unscheduled after they are fired, which means that we wouldn’t be able to retrieve past-due items. We’ll have to use another method to persist our items, and we need a way to associate an item we’ve retrieved from the disk with its corresponding local notification. For that, we’ll use a universally unique identifier (UUID).

struct TodoItem {
    var title: String
    var deadline: Date
    var UUID: String

    init(deadline: Date, title: String, UUID: String) {
        self.deadline = deadline
        self.title = title
        self.UUID = UUID
    }
}

Since we’re going to display overdue items in red, lets also add a convenience method that returns whether or not an item is overdue.

var isOverdue: Bool {
    // Optionally, you can omit "ComparisonResult" and it will be inferred.
    return (Date().compare(self.deadline) == ComparisonResult.orderedDescending) // deadline is earlier than current date
}

Saving To-Do Items (Scheduling Notifications)

We need a class to represent the list of items and handle persisting them. Create a new Swift file named “TodoList”.

Our application is only concerned with maintaining a single to-do list, so it makes sense to make a single shared instance available throughout the app.

class TodoList {
    class var sharedInstance : TodoList {
        struct Static {
            static let instance: TodoList = TodoList()
        }
        return Static.instance
    }
}

This method is the community-accepted way to implement the singleton pattern in Swift, which you can adapt to your own projects. If you’re curious, you can read the details about what it’s doing and why in this Stack Overflow answer.

UserDefaults provides a simple way to persist our to-do items to disk. The following snippet defines a method that adds a dictionary representation of a to-do item to standard user defaults (with UUID as the key), and then creates the associated local notification.

fileprivate let ITEMS_KEY = "todoItems"
func addItem(_ item: TodoItem) {
    // persist a representation of this todo item in UserDefaults
    var todoDictionary = UserDefaults.standard.dictionary(forKey: ITEMS_KEY) ?? Dictionary() // if todoItems hasn't been set in user defaults, initialize todoDictionary to an empty dictionary using nil-coalescing operator (??)
    todoDictionary[item.UUID] = ["deadline": item.deadline, "title": item.title, "UUID": item.UUID] // store NSData representation of todo item in dictionary with UUID as key
    UserDefaults.standard.set(todoDictionary, forKey: ITEMS_KEY) // save/overwrite todo item list
 
    // create a corresponding local notification
    let notification = UILocalNotification()
    notification.alertBody = "Todo Item \"\(item.title)\" Is Overdue" // text that will be displayed in the notification 
    notification.alertAction = "open" // text that is displayed after "slide to..." on the lock screen - defaults to "slide to view" 
    notification.fireDate = item.deadline as Date // todo item due date (when notification will be fired) notification.soundName = UILocalNotificationDefaultSoundName // play default sound 
    notification.userInfo = ["title": item.title, "UUID": item.UUID] // assign a unique identifier to the notification so that we can retrieve it later
 
    UIApplication.shared.scheduleLocalNotification(notification)
}

Notice that we’re just playing the default sound when the notification fires. You can provide your own sound file, but audio files over 30 seconds in length are not supported. The default sound will play instead.

We’re almost to the point where users can create new list items. It’s time to implement savePressed: in TodoSchedulingViewController.

@IBAction func savePressed(_ sender: UIButton) {
    let todoItem = TodoItem(deadline: deadlinePicker.date, title: titleField.text!, UUID: UUID().uuidString)
    TodoList.sharedInstance.addItem(todoItem) // schedule a local notification to persist this item
    let _ = self.navigationController?.popToRootViewController(animated: true) // return to list view
}

Note that, since this is a new to-do list entry, we’re passing in a newly generated UUID.

Try out the app now. Launch it in the simulator, create a new item due a minute in the future, and return to the home or lock screen (Shift-CMD-H or CMD-L) to view the notification. The notification won’t necessarily fire right on the stroke of the minute (due to a hidden ‘seconds’ value on the time picker control), but you’ll see it within the minute.

iOS Simulator Screen Shot Feb 3, 2015, 4.29.05 PMiOS Simulator Screen Shot Feb 3, 2015, 4.33.13 PM

The 64 Notification Limit

It’s important to note that you’re limited to scheduling 64 local notifications. If you schedule more, the system will keep the 64 soonest firing notifications and automatically discard the rest.

We can avoid running into this issue by disallowing the creation of new items if 64 already exist.

In TodoTableViewController:

func refreshList() {
    todoItems = TodoList.sharedInstance.allItems()
    if (todoItems.count >= 64) {
        self.navigationItem.rightBarButtonItem!.enabled = false // disable 'add' button
    }
    tableView.reloadData()
}

Retrieving To-Do Items

The fact that to-do items are persisted as an array of dictionaries is an implementation detail that outside classes shouldn’t have to worry about. Our TodoList class needs a public facing function that the list view controller can query to retrieve a list of to-do items.

func allItems() -> [TodoItem] {
    let todoDictionary = UserDefaults.standard.dictionary(forKey: ITEMS_KEY) ?? [:]
    let items = Array(todoDictionary.values)
    return items.map({
        let item = $0 as! [String:AnyObject]
        return TodoItem(deadline: item["deadline"] as! Date, title: item["title"] as! String, UUID: item["UUID"] as! String!)
    }).sorted(by: {(left: TodoItem, right:TodoItem) -> Bool in
        (left.deadline.compare(right.deadline) == .orderedAscending)
    })
}

This function retrieves the array of item representation from disk, converts it to an array of TodoItem instances using an unnamed closure we pass to map, and sorts that array chronologically. Describing the map and sort functions in detail is beyond the scope of this tutorial, but you can find more information in the Swift language guide’s section on closures.

Now we can hook up TodoTableViewController to display the list.

class TodoTableViewController: UITableViewController {
    var todoItems: [TodoItem] = []
    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        refreshList()
    }

    func refreshList() {
        todoItems = TodoList.sharedInstance.allItems()

        if (todoItems.count >= 64) {
            self.navigationItem.rightBarButtonItem!.enabled = false // disable 'add' button
        }
        tableView.reloadData()
    }

    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return todoItems.count
    }

    override func tableView(_ tableView: UITableView, cellForRowAtIndexPath indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "todoCell", for: indexPath) // retrieve the prototype cell (subtitle style)
        let todoItem = todoItems[(indexPath as NSIndexPath).row] as TodoItem
        cell.textLabel?.text = todoItem.title as String!
        if (todoItem.isOverdue) { // the current time is later than the to-do item's deadline
            cell.detailTextLabel?.textColor = UIColor.red
        } else {
            cell.detailTextLabel?.textColor = UIColor.black // we need to reset this because a cell with red subtitle may be returned by dequeueReusableCellWithIdentifier:indexPath:
        }

        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "'Due' MMM dd 'at' h:mm a" // example: "Due Jan 01 at 12:00 PM"
        cell.detailTextLabel?.text = dateFormatter.string(from: todoItem.deadline as Date)
        return cell
    }
}

Our to-do list now shows each item in chronological order, with the date label in red if the item is overdue.

iOS Simulator Screen Shot Feb 4, 2015, 10.26.58 PM

There are two issues we need to deal with here. Users currently don’t receive any visual feedback that a notification has fired (and a to-do item is overdue) when the app is running in the foreground. Also, when the app resumes, the list won’t automatically be refreshed, meaning that missed deadlines may not appear in red. Lets solve both issues now.

In TodoTableViewController:

override func viewDidLoad() {
    super.viewDidLoad()
    NotificationCenter.default.addObserver(self, selector: #selector(TodoTableViewController.refreshList), name: NSNotification.Name(rawValue: "TodoListShouldRefresh"), object: nil)
}

In AppDelegate:

func application(_ application: UIApplication, didReceive notification: UILocalNotification) {
    NotificationCenter.default.post(name: Notification.Name(rawValue: "TodoListShouldRefresh"), object: self)
}
func applicationDidBecomeActive(_ application: UIApplication) {      
    NotificationCenter.default.post(name: Notification.Name(rawValue: "TodoListShouldRefresh"), object: self)
}

Please note that, despite the presence of the word “notification”, NotificationCenter is unrelated to UILocalNotification. NotificationCenter’s purpose is to provide a simple way to implement the observer pattern in your apps.

Here we register TodoTableViewController as an observer to the “TodoListShouldRefresh” notification. Whenever a notification with that name is posted, the reloadData method will be called.

I’ve omitted this step, but it is generally better to define notification names as static constants to avoid repeating yourself.

Completing To-Do Items (Canceling Notifications)

Our to-do list application isn’t very useful without a way to clear out completed items, and the simplest way to do that is to delete them. We need to add some functionality to TodoList.

func removeItem(_ item: TodoItem) {
    let scheduledNotifications: [UILocalNotification]? = UIApplication.shared.scheduledLocalNotifications
    guard scheduledNotifications != nil else {return} // Nothing to remove, so return
 
    for notification in scheduledNotifications! { // loop through notifications...    
        if (notification.userInfo!["UUID"] as! String == item.UUID) { // ...and cancel the notification that corresponds to this TodoItem instance (matched
            UIApplication.shared.cancelLocalNotification(notification) // there should be a maximum of one match on UUID
            break
        }
    }

    if var todoItems = UserDefaults.standard.dictionaryForKey(ITEMS_KEY) {
        todoItems.removeValue(forKey: item.UUID)
        UserDefaults.standard.set(todoItems, forKey: ITEMS_KEY) // save/overwrite todo item list
    }
}

Note that passing an existing notification to scheduleLocalNotification: will cause a duplicate to be created. If you want to give users the ability to edit existing local notifications, you’ll need to retrieve the old one and cancel it before scheduling the new one.

Now we just need to allow users to remove items by swiping the item’s cell and pressing “Complete”.

In TodoTableViewController:

override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
    return true // all cells are editable
}
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
    if editingStyle == .delete { // the only editing style we'll support
        // delete the row from the data source
        let item = todoItems.remove(at: (indexPath as NSIndexPath).row) // remove TodoItem from notifications array, assign removed item to 'item'
        tableView.deleteRows(at: [indexPath], with: .fade) 
        TodoList.sharedInstance.removeItem(item) // delete backing property list entry and unschedule local notification (if it still exists) 
        self.navigationItem.rightBarButtonItem!.isEnabled = true // we definitely have under 64 notifications scheduled now, make sure 'add' button is enabled
    }
}

iOS Simulator Screen Shot Feb 4, 2015, 10.26.58 PM

Conclusion

We now have a working to-do list application that lets our users schedule and cancel local notifications with sound and custom alert messages. The source code can be downloaded here.

In part 2 of this series, which builds on this project, we’ll add support for an application icon badge and learn about notification actions, a new feature that allows us to trigger code from a notification without ever opening the app.

Go to part 2 now »


Sign up now and get a set of FREE video tutorials on writing iOS apps coming soon.



Subscribe via RSS

Local Notifications in iOS 9+ with Swift (Part 2)

This post has been updated for compatibility with XCode 8 and iOS 10

In part 1 of this series, we created a simple to-do list application that used local notifications to alert users when to-do items were overdue. This time, we’re going to build on that the project by enabling application icon badges to display the number of overdue items and add support for notification actions, allowing our users to complete and edit to-do items without even opening the app.

You can download the source code for part 1 here.

Badging the App Icon

It bears mentioning that we can badge the app icon without using local notifications. The applicationWillResignActive: method in AppDelegate is a good place to do so, since it will be fired just before the user returns to the home screen where they can see the app icon.

func applicationWillResignActive(_ application: UIApplication) { // fired when user quits the application
    let todoItems: [TodoItem] = TodoList.sharedInstance.allItems() // retrieve list of all to-do items
    let overdueItems = todoItems.filter({ (todoItem) -> Bool in
        return todoItem.deadline.compare(Date()) != .orderedDescending
    })
    UIApplication.shared.applicationIconBadgeNumber = overdueItems.count // set our badge number to number of overdue items
}

iOS Simulator Screen Shot Feb 4, 2015, 10.31.14 PM iOS Simulator Screen Shot Feb 4, 2015, 11.51.25 PM

This is a good start, but we need the badge number to automatically update when to-do items become overdue. Unfortunately, we can’t instruct the app to simply increment the badge value when our notifications fire, but we can pre-compute and provide a value for the “applicationIconBadgeNumber” property of our local notifications. Lets provide a method in TodoList to set an associated badge number for each notification.

func setBadgeNumbers() {
    let scheduledNotifications: [UILocalNotification]? = UIApplication.shared.scheduledLocalNotifications // all scheduled notifications
    guard scheduledNotifications != nil else {return} // nothing to remove, so return
 
    let todoItems: [TodoItem] = self.allItems()
 
    // we can't modify scheduled notifications, so we'll loop through the scheduled notifications and
    // unschedule/reschedule items which need to be updated.
    var notifications: [UILocalNotification] = []

    for notification in scheduledNotifications! {
        print(UIApplication.shared.scheduledLocalNotifications!.count)
        let overdueItems = todoItems.filter({ (todoItem) -> Bool in // array of to-do items in which item deadline is on or before notification fire date
            return (todoItem.deadline.compare(notification.fireDate!) != .orderedDescending)
        })

        // set new badge number
        notification.applicationIconBadgeNumber = overdueItems.count 
        notifications.append(notification)
    }
 
    // don't modify a collection while you're iterating through it
    UIApplication.shared.cancelAllLocalNotifications() // cancel all notifications
 
    for note in notifications {
        UIApplication.shared.scheduleLocalNotification(note) // reschedule the new versions
    }
}

There’s no way to update a scheduled notification, but you can achieve the same effect by simply canceling the notification, making your changes and rescheduling it.

The applicationIconBadgeNumber property can accept values up to 2,147,483,647 (NSIntegerMax), though anything over five digits will be truncated in the icon badge. Setting it to zero or a negative number will result in no change.

Screen Shot 2015-02-04 at 11.36.36 PMScreen Shot 2015-02-04 at 11.38.14 PM

Now we just need to call this method when our to-do list changes. Add the following line to the bottom of addItem: and removeItem: in TodoList

self.setBadgeNumbers()

Now, when a notification fires, the badge number will be automatically updated.

Repeating Notifications

UILocalNotificaiton instances have a repeatInterval property that we can use to, unsurprisingly, repeat a notification at a regular interval. This is a good way to get around the 64 notification limit in some cases; a repeating notification is only counted against it once.

Unfortunately, we have to choose between using repeatInterval and applicationIconBadgeNumber in this app. Badge numbers are set on the application icon each time a notification is fired. Older notifications could end up “out of phase” with newer notifications and actually lower the badge number when repeated. We could get around this by scheduling two notifications for each to-do item, a repeating notification that displays the alert and plays the sound, and a non-repeating notification that updates the badge count, but this would cut the number of to-do items we could schedule in half.

The biggest limitation with repeating notifications is that the repeatInterval doesn’t accept a custom time interval. You have to provide an NSCalendarUnit value like “HourCalendarUnit” or “DayCalendarUnit”. If you want a notification to fire every 30 minutes, for example, you’ll have to schedule two notifications (offset by 30 minutes) and set them both to repeat hourly. If you want it to fire every 31 minutes, then you’re out of luck.

Performing Actions in the Background

iOS 8 introduced a really useful new feature, notification actions, which let our users trigger code execution without even having to open the app. Lets give our users the ability to complete and schedule reminders for to-do items directly from the notification banner.

iOS Simulator Screen Shot Feb 6, 2015, 12.43.34 AM iOS Simulator Screen Shot Feb 6, 2015, 12.43.37 AM

In AppDelegate:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
    let completeAction = UIMutableUserNotificationAction()
    completeAction.identifier = "COMPLETE_TODO" // the unique identifier for this action
    completeAction.title = "Complete" // title for the action button
    completeAction.activationMode = .background // UIUserNotificationActivationMode.Background - don't bring app to foreground
    completeAction.isAuthenticationRequired = false // don't require unlocking before performing action
    completeAction.isDestructive = true // display action in red
 
    let remindAction = UIMutableUserNotificationAction()
    remindAction.identifier = "REMIND"
    remindAction.title = "Remind in 30 minutes"
    remindAction.activationMode = .background
    remindAction.isDestructive = false
 
    let todoCategory = UIMutableUserNotificationCategory() // notification categories allow us to create groups of actions that we can associate with a notification
    todoCategory.identifier = "TODO_CATEGORY"
    todoCategory.setActions([remindAction, completeAction], for: .default) // UIUserNotificationActionContext.Default (4 actions max)
    todoCategory.setActions([completeAction, remindAction], for: .minimal) // UIUserNotificationActionContext.Minimal - for when space is limited (2 actions max)

    // we're now providing a set containing our category as an argument
    application.registerUserNotificationSettings(UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: Set([todoCategory])))
    return true
}

Notice that we’re calling todoCategory.setActions() twice, once for each of the two available action contexts. If your users are displaying notifications from your app as banners, then the actions in the minimal context will be displayed. If notifications are displayed as alerts (the “default” context), up to four actions will be displayed.

iOS Simulator Screen Shot Feb 6, 2015, 12.41.20 AM iOS Simulator Screen Shot Feb 6, 2015, 12.06.33 AM

The order of the actions in the array we pass to setActions: is the order that the actions will be displayed in the UI, though, oddly, the items are ordered right-to-left in the minimal context.

Lets make sure to set this category for the notification we’re scheduling in TodoList’s addItem: method.

notification.category = "TODO_CATEGORY"

We already have a method for “completing” to-do items, removeItem:, but we need to implement one for scheduling a reminder in TodoList.

func scheduleReminder(forItem item: TodoItem) {
    let notification = UILocalNotification() // create a new reminder notification
    notification.alertBody = "Reminder: Todo Item \"\(item.title)\" Is Overdue" // text that will be displayed in the notification
    notification.alertAction = "open" // text that is displayed after "slide to..." on the lock screen - defaults to "slide to view"
    notification.fireDate = Date(timeIntervalSinceNow: 30 * 60) // 30 minutes from current time
    notification.soundName = UILocalNotificationDefaultSoundName // play default sound
    notification.userInfo = ["title": item.title, "UUID": item.UUID] // assign a unique identifier to the notification that we can use to retrieve it later
    notification.category = "TODO_CATEGORY"
 
    UIApplication.shared.scheduleLocalNotification(notification)
}

Note that we aren’t changing the due date on the to-do item (or trying to cancel the original notification – it’s been automatically removed). Now we just have to jump back to AppDelegate and implement a handler for the actions:

func application(_ application: UIApplication, handleActionWithIdentifier identifier: String?, for notification: UILocalNotification, completionHandler: @escaping () -> Void) {
    let item = TodoItem(deadline: notification.fireDate!, title: notification.userInfo!["title"] as! String, UUID: notification.userInfo!["UUID"] as! String!)
    switch (identifier!) {
    case "COMPLETE_TODO":
        TodoList.sharedInstance.remove(item)
    case "REMIND":
        TodoList.sharedInstance.scheduleReminder(forItem: item)
    default: // switch statements must be exhaustive - this condition should never be met
        print("Error: unexpected notification action identifier!")
    }
    completionHandler() // per developer documentation, app will terminate if we fail to call this
}

Go ahead and try it out now (you may want to pass a lower value to dateByAddingTimeInterval: for testing purposes).

iOS Simulator Screen Shot Feb 6, 2015, 1.25.36 AM

We’ve covered all of the non-geographic functionality of UILocalNotification and now have a pretty full-featured to-do list app, so this concludes our series. You can download the full source code for this project from here.


Sign up now and get a set of FREE video tutorials on writing iOS apps coming soon.



Subscribe via RSS

Swift 1.2 and Xcode 6 Beta 2 – The best update yet

The big news in the Swift community is the release of Swift 1.2, featuring some awesome features. Apple wrote about that a bit here, this was before they released Xcode 6.3 Beta 2, which came out today. But it contains most of the major language changes.

Xcode 6.3 Beta 2

First of all, Xcode itself has changed to allow for more easy to use playgrounds. In particular Apple has added rich text comments, in addition to showing results inline rather than in a separate timeline view. Swift performance was also further improve, and an additional method called zip was introduced for merging Swift sequences together.

zip()

Zip is a method that comes straight out of Haskell which accepts multiple sequences of data, and returns a single tuple “zipping” the two data sets together. For example

let a = [1,2,3]
let b = ["a","b","c"]
let zipped = zip(a, b)

Here the value of zipped would become two sequences in a tuple with types [Int] and [String]. Casting this to an Array makes the significance of this a little more clear:

println(Array(zipped))

[(1, a), (2, b), (3, c)].
As you can see the two sequences are simply “zipped” together. This does beg the question though, what if the sequences are of differing lengths?
For example…

let a = [1,2,3]
let b = ["a","b"]
let zipped = zip(a,b)

In this case, the zipping process will use the shortest sequence’s length as the number of elements to zip, and simply discard the trailing elements on the longer sequence. Giving the output, [(1, a), (2, b)]

This is particularly useful when working with what are effectively infinite sequences. You can limit the list by zipping with a finite sequence:

    let squares = Array(map(1..<10) { $0 * $0 })
    let names = ["one", "two", "three"]
    
    let squareList = zip(names, squares)
    
    println(Array(squareList))

Results in:
[(one, 1), (two, 4), (three, 9)]

So, even though the squares sequence can go on forever, it's made in to a finite list due to the fact that names has only 3 elements.

Goodbye pyramid of doom!

The optional binding sometimes leads to messy code like this:

if let first = user.first {
  if let last = user.last {
    return "\(first) \(last)"
  }
}

But with 1.2, these series of if let statements can be collapsed down to just a comma separated list of optional values, and only a single set of curly braces. The above code will behave exactly the same as this:

if let first = user.first, last = user.last {
  return "\(first) \(last)"
}

Sometimes these chains upon chains of optional binding statements can get out of hand, so this is a very welcome feature. As an additional bonus in Xcode 6.3 Beta 2, we can now also add a single optional binding let clause. For example:

if age > 17 && profile.public,
  let first = user.first,
  last = user.last {
    return "\(first) \(last)"
}

This code will not only perform the optional binding in a more concise way with the variables first and last, but it will only do so if the user is of age and has a public profile available, which are assumed to be boolean values in this example. Contrast that with how we wrote this in older versions:

if (age > 17 && profile.public) {
  if let first = user.first {
    if let last = user.last {
      return "\(first) \(last)"
    }
  }
}

The as! keyword was added

When casting from one type to the other, it's possible that the cast could fail. Previously this was handled with the case of an optional using the as? operator. Consider the scenario below

func bio(name: String, location: String) -> String {
  ...
}

var name: AnyObject
name = "Jameson"
var location = "Austin, TX"
let nameStr = name as String
bio(nameStr, location)

Here we are calling a function that requires a String, but we have name typed as an AnyObject object. Before Swift 1.2 this code would be accepted, but this could actually crash your application if the cast fails. In this case it would never fail, so we can safely do this cast, but the syntax shown above does not clearly demonstrate that this cast is actually dangerous. If name gets changed to something that is not castable to a String later, this code would cause the app to crash. In order to more clearly communicate this, the as operator must now become as! if the cast could possibly fail. So the above would now become this:

func bio(name: String, location: String) -> String {
  ...
}

var name: AnyObject
name = "Jameson"
var location = "Austin, TX"
let nameStr = name as! String
bio(nameStr, location)

This helps drive home an important message: If you are using an exclamation mark (!), then you may be setting up a situation where the app could crash due to a failed cast, or null value. As a general rule, you should just never use forced casts unless you absolutely have to (or if you're writing code that won't go in to production)

Keep in mind the as? keyword is unchanged, and in general you should prefer using it in addition to an optional binding for this type of scenario, as this is much safer, e.g.

func bio(name: String, location: String) -> String {
  ...
}

var name: AnyObject
name = "Jameson"
var location = "Austin, TX"
if let nameStr = name as? String {
  bio(nameStr, location)
}

Xcode and Compiler Improvements
This is probably the biggest one for me. The compiler is faster due to incremental builds, and Xcode doesn't crash all the time due to some stability improvements. This alone makes the beta work the download and I highly recommend getting a copy on iOS Dev Center.

Want to learn more about Swift 1.2? Try out some of my free tutorials. My Core Data tutorial was updated recently for 1.2, which I would recommend to anyone interested in working on real iOS Apps.


Sign up now and get a set of FREE video tutorials on writing iOS apps coming soon.



Subscribe via RSS

Core Animation Swift Tutorial – Animatable Properties

This tutorial series requires a basic understanding of UIView hierarchy. If you are new to iOS development, you might want to begin with Developing iOS Apps Using Swift first.

When you first hear about Core Animation, you might think it is all about animation. However, animation is only a part of this framework. Core Animation is an infrastructure for compositing and manipulating visual content onscreen. It uses the GPU to accelerate the rendering of on-screen objects. It divides the content onscreen into individual objects called layers, and arranges them in a tree hierarchy (known as the layer tree). You are familiar with the UIView tree hierarchy, which is built upon the layer tree. In other words, Core Animation accounts for everything that you see onscreen.

In the first part of this tutorial series, you are going to learn the basics of CALayer, how to use its properties to create neat visual effects easily, and at the end of this tutorial, you will learn the most important subclass of CALayer – CAShapeLayer.

What Is CALayer?

CALayers are rectangular objects that can contain visual content. They are stored into a tree hierarchy, and each manages the position of its children sublayers.

Sound familiar? You may say, “It’s like UIView!”

That’s true, but it’s not just a coincidence. Every UIView has a layer property known as the backing layer, which is an instance of CALayer. UIView just ensures the corresponding back layers are correctly connected in the layer tree when subviews are added or removed from the view. It is the backing layer that is responsible for display and animation of the view. The only major feature that the backing layer does not handle is user interaction.

For the purposes of going through this tutorial, I recommend creating an empty single-view iPhone application.

Exploring CALayer

Creating a CALayer instance is very straightforward.

let redLayer = CALayer()

We can set its frame, backgroundColor, and add it to a superlayer just like we do with UIView.

redLayer.frame = CGRect(x: 50, y: 50, width: 100, height: 100)
redLayer.backgroundColor = UIColor.redColor().CGColor
layer.addSublayer(redLayer)

Add this code to a function called setup in the file ViewController.swift, and call the method from viewDidLoad. You should have something like this:

import UIKit

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        setup()
    }
    func setup() {
        let redLayer = CALayer()
        
        redLayer.frame = CGRect(x: 50, y: 50, width: 50, height: 50)
        redLayer.backgroundColor = UIColor.redColor().CGColor
        self.view.layer.addSublayer(redLayer)
    }
}

Notice that the backgroundColor property of CALayer is a CGColor instead of UIColor.

You can also set an image as the content via the contents property. contents is also known as backing image.

We’ll use an image of a butterfly:

Note that you’ll have to drag your image named ButterflySmall.jpg in to your Xcode project hierarchy in order for the UIImage() command to find the picture.

func setup() {
    let redLayer = CALayer()
    
    redLayer.frame = CGRect(x: 50, y: 50, width: 50, height: 50)
    redLayer.backgroundColor = UIColor.redColor().CGColor
    self.view.layer.addSublayer(redLayer)
    
    
    let imageLayer = CALayer()
    let image = UIImage(named: "ButterflySmall.jpg")!
    imageLayer.contents = image.CGImage
    
    imageLayer.frame = CGRect(x: 0, y: 100, width: image.size.width, height: image.size.height)
    imageLayer.contentsGravity = kCAGravityResizeAspect
    imageLayer.contentsScale = UIScreen.mainScreen().scale
    
    self.view.layer.addSublayer(imageLayer)
}

contentsGravity is a constant that specifies how the layer’s contents are positioned or scaled within its bounds.

contentsScale defines a ratio mapping between the size of the layer (measured in points) and the size of the bitmap used to present the layer’s content (known as backing image, measured in pixels). The default value is 1.0. Normally we set the value as the scale of the image, as shown above. However, when working with image that are generated programmatically, or image that missing @2x/@3x suffix, you will remember to manually set the layer’s contentsScale to match the screen scale. Otherwise, you will get a pixelated image on your device.

Corners and Border

CALayer has a property called cornerRadius, which applies rounded corners to the layer’s background and border. When the masksToBounds property is set to true, the layer’s backing image and sublayers are clipped to this curve.

On our redLayer, let’s apply some rounded corners, and make the border visible.

func setup() {
    let redLayer = CALayer()
    
    redLayer.frame = CGRect(x: 50, y: 50, width: 50, height: 50)
    redLayer.backgroundColor = UIColor.redColor().CGColor
    
    // Round corners
    redLayer.cornerRadius = 25
    
    // Set border
    redLayer.borderColor = UIColor.blackColor().CGColor
    redLayer.borderWidth = 10
    ...

borderWidth, borderColor defines the width and color of a layer’s border.

Drop Shadow

There are four properties that you could configure the drop shadow for a layer, shadowOpacity, shadowColor, shadowOffset and shadowRadius . shadowRadius controls the blurriness of the shadow. A larger value could create a softer shadow that looks more natural.

Let’s add a shadow to our redLayer as well.

redLayer.shadowColor = UIColor.blackColor().CGColor
redLayer.shadowOpacity = 0.8
redLayer.shadowOffset = CGSizeMake(2, 2)
redLayer.shadowRadius = 3

Unlike the layer border, the layer’s shadow derives from the exact shape of its contents, not just the bounds and cornerRadius. However, if you know what the shape of your shadow would be in advance, you could specify it via shadowPath (an instance of CGPath). You could improve performance by doing this.

Animating Layers

Now that we’ve covered a few of the types of properties that are present in Core Animation, let’s quickly walk through creating some actual animations.

// Create a blank animation using the keyPath "cornerRadius", the property we want to animate
let animation = CABasicAnimation(keyPath: "cornerRadius")

// Set the starting value
animation.fromValue = redLayer.cornerRadius

// Set the completion value
animation.toValue = 0

// How may times should the animation repeat?
animation.repeatCount = 1000

// Finally, add the animation to the layer
redLayer.addAnimation(animation, forKey: "cornerRadius")

Here we create a new CABasicAnimation for the cornerRadius property. Run your app and take a look, cool right?

You could just as easily make this animation apply to any other animatable property of CALayer. Try swapping the “cornerRadius” keyPath value in the CABasicAnimation() constructor with the value “borderWidth”. What happens? What about a value of “shadowRadius”?

From this tutorial you can see how the basics of Core Animation work. In the next part we’ll move on to learn about more animatable properties, and how to work with masks to do really nifty effects.

Full code for this tutorial available here, on Github.

Want to get notified when the next part is out? Be sure to subscribe to our newsletter here.


Sign up now and get a set of FREE video tutorials on writing iOS apps coming soon.



Subscribe via RSS

Should I learn Objective-C or Swift first?

“Should I learn Objective-C or Swift first?”

I get asked this question a lot. Sometime’s people will also ask about learning C or C++ first. So, I want to take a moment and give you the low-down on how I feel as a professional iOS & Mac developer, six months after Swift’s introduction. If this is your first time here, here’s a little background on me:

About me…

I’ve been developing software for as long as I can remember, at least 20 years now. I never was really the Mac guy, but I liked Linux and was always looking at new technologies. So, when the iPhone came out in 2008, I got myself a Mac and entered that ecosystem. Around that time I learned Objective-C, and that became my primary development language. It has been since then, and I’ve seen the language and Mac/iOS APIs twist and turn this way and that for the past 6+ years. In June I picked up Swift for the first time like everyone else, and although I still won’t call myself an expert, I will say I’ve done extensive study on the language. I’ve developed (and released) 3 apps using Swift since the announcement. Learning Swift is something I think is really important to iOS developers now, in fact it’s critical. To help people out I decided to write my Swift Book. This also serves as a way to help me learn the language, but I have already seen what a valuable resource it is for others; it’s exciting to be a part of… Additionally I’ve worked on an SDK that uses Swift, which will be used as part of a major platform worldwide in 2015. It’s very exciting to ship something like this that so many other developers will be using.

So, that’s my Swift-related experience in a nutshell. Now, here’s how I want to answer your question…

So… Swift or Objective-C?

Part of me wants to say, “Yes, go learn C first and then Objective-C. That’s what I did, so that’s what you should do.”

But here’s the thing: Just because that’s the path I took, doesn’t mean it’s the best path today. When I was first learning C, people told me I needed to learn Assembly to really get what was going on. They told me that without an underlying understanding of Assembly, I was going to be forever writing code and not understanding it. I ended up ignoring this advice and was very happy and successful as a developer without Assembly knowledge. In my college years, I finally picked up Assembly as part of my Electrical Engineering degree program. It helped enlighten some things, but for the most part I don’t feel knowing Assembly had much of an effect on my day-to-day programming. It had no effect on how I separate objects, how I decide what gets encapsulated, where to inherit, or where to compose. Most importantly, it didn’t help me to build better software. It was basically just academic, and as interesting as it was and is, the only place it’s even remotely relevant day-to-day is in debugging or reverse engineering; and only in limited capacities.

There’s certainly some sort of fear in me, like if we don’t all learn Assembly it will become a lost art. But, I don’t think that’s a realistic concern, honestly. The more I think about the idea of Assembly becoming a lost art the more I realize it will never happen. A single preserved book on the topic can get anyone where they need to be to be productive in Assembly, you just probably don’t want to.

Computer Science is an industry where we need to let go of the past, and we need to do it as quickly as we can. This industry is not going to wait for you to learn all the languages leading up to the latest and greatest. The marketplace certainly won’t reward that. What it will reward though, is knowing how to write code to make working software. That’s sort of the general thesis of this site, and it’s why I produce it. I don’t want to teach you to write code; I want to teach you to make software.

So here’s my answer to your question:

Swift

You should learn Swift first. You should learn it first because it’s the future of development on Apple platforms, and frankly it’s just easier to understand than Obj-C or C. What you may find as you learn it is that the Cocoa framework is getting a little stale. It’s starting to look very much like an Objective-C API in a Swift world. But that’s probably going to change. This wouldn’t be the first time Apple made a major change to their underlying APIs. Back in the days before Cocoa developers used Carbon, a C-based API that had some interoperability with Objective-C.

Apple is well-known for making swift (get it?) changes to their development stack. The move from Mac OS 9 to Mac OS X is a great example of their commitment to innovation. As a developer on Apple platforms, it’s important to understand this fact. Apple is about building the future of technology products, and they are not afraid to forego backwards-compatibility in order to achieve that. If you are still writing Objective-C day-to-day, you’re writing legacy code at this point. If you are writing Swift, then welcome to our world, you are the future.


Sign up now and get a set of FREE video tutorials on writing iOS apps coming soon.



Subscribe via RSS