Cheating on Swift Substrings

If you found yourself needing to get a substring of a String in Swift before you got around to the relavant chapter of the book you were probably left scratching your head for a bit. How could something so conceptually simple be so akward to perform?

Here’s a great article explaining how to find a substring in Swift, from Natasha The Robot.

It turns out that Swift Strings are much cooler than your old fashioned strings from other languages, and Swift Ranges are even cooler still. But unless you’re using them frequently, I find that

str.substringWithRange(Range(start: (advance(str.endIndex, -1)), end: str.endIndex))
````

doesn't exactly roll off the tongue.

So here's my cheat, which is to not use String at all. Arrays in Swift can be chopped up using plain integer ranges, and a String is just an `Array<character>`. Swift even lets you iterate over the contents of a String and access each Character in turn, but it doesnt give you String subscripting.

So theres a couple of cheat options, implement subscript on String yourself, or what I preferred, extend String to give you quick access to an Array representation of the String.

extension String { func asArray() -> [Character] {

    var array : [Character] = []
    for char in self {
        array.append(char)
    }
    return array
}

}


You can then do fun stuff like this, which for me, reads very nicely.

let str = “Coma inducing corporate bollocks” str.asArray().last // “s” str.asArray()[10] // “i” String(str.asArray()[2..<7]) // “ma in” ```

You don’t need to break out the big O notation to see this isn’t going to perform great, you’re iterating over the entire string everytime you want to get a piece of it, then the array methods are going to go do it again, so use with caution!

Death By Date Format String

Recently I learned that you probably always want “yyyy” and not “YYYY”.

let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "YYYY-MM-dd"

println(dateFormatter.stringFromDate(
   dateFormatter.dateFromString("2015-12-26")!))

This prints 2015-12-26. Obviously. So what about

println(dateFormatter.stringFromDate(
   dateFormatter.dateFromString("2015-12-27")!))

It prints 2016-12-27.

Note that the year is 2016.

I was fortunte1 enough to get assinged a production crash bug this week that after a long day of head scratching, turned out to be caused by this.

Interestingly, the NSDate created with the format is the date I expected, it represents 27 December 2015 and it’s only getting a string from the date with that format that gives you the ‘wrong’ year. Similarly an NSDate constructed in any other way that represents 27 December 2015 will behave the same.

The NSDateFormatter docs point you at Unicode Technical Standard Number 35 for the definitions of date format strings. I’ve looked at this before and I expect I’m not alone in having paid more attention to the day and month parts of the format. They’re usually what we’re interested in because the year is always the year, at most we might prefer 2 or 4 digits but thats about as interesting as it gets. I suspect what happens fairly often (and what probably happened with our bug) was that the developer guessed at YYYY as the year format, and when it appeared to work just fine, assumed it was correct.

The relavant part of that standard states that y is the year, but Y is

Year (in “Week of Year” based calendars) … May not always be the same value as calendar year.

And the problem is that, as far as I can tell, it almost always is the same as the calendar year. The last few days of the year are the only ones I’ve seen causing problems. If it was more different, it would be spotted easier and perhaps I would have already known that YYYY was wrong and spotted that as the error right away.


  1. If I consider it a learning opportunity and not an annoying time suck of a bug! [return]

Optional Optionals

So here’s a confusing sentence.

With Swift functions you can have optional parameters, you can also have parameters that are optionals, and you can have optional parameters that are optionals.

A rather confused looking Donald Rumsfeld

Not taking the time to think about the 3 different levels of optionality in function parameters had me scratching my head for a few minutes today, but all the options (sorry) are useful and it’s not at all confusing once you remember them.

My scenario was that I created a function that does some stuff and then executes a closure supplied by the caller. Something like

func doSomeStuff(thenDoThis:()->())

Which a caller would call like

doSomeStuff {
	// and then do this stuff
}

But I want to let the caller decide whether they want to supply the closure or not, so if they like they could just call the function and be done.

doSomeStuff()

So let’s make the closure optional. Easy, as with any type in Swift, we can mark it optional by including a ?

func doSomeStuff(thenDoThis:(()->())?)

So then if we go ahead and call

doSomeStuff() // Error: Missing argument for parameter #1 in call

But it was optional, so why the error? Well it wasn’t optional in the sense that I could leave it out, it’s just that it was an optional type which we are still expected to provide every time. As our type is an optional closure with no parameters and no return, we have to supply a closure with no parameters and no return or nil. So we’d actually have to call

doSomeStuff(nil) // this works fine but isn't what we want

So how do you create an optional parameter, one that a caller can decide to leave out? To do that you provide a default value to be used for that parameter, right in the function declaration.

func doSomeStuff(thenDoThis:()->() = defaultClosure)

This means that if the caller doesn’t supply a value for thenDoThis we’ll use defaultClosure instead (assuming defaultClosure is defined elsewhere as a ()->().) We can now happily call the following if we don’t want to supply a closure.

doSomeStuff() // yay!

The behaviour I was interested in though was that if I didn’t supply a closure, that there would be no closure executed at all, not that some other one I had to define would be called instead. Well, I could just make defaultClosure do nothing, or just have the default value be {} like

func doSomeStuff(thenDoThis:()->() = {})

Which is fine, and maybe even the preferred way, but you can also have an optional optional parameter, and have it’s default value be nil.

func doSomeStuff(thenDoThis:(()->())? = nil)

Now if the caller omits the closure, thenDoThis will be nil, which makes more sense to me in this situation.