3

What's the difference between these two declarations? Which one is better? Why?

... error = some NSError ...

1.

var newUserInfo: [NSObject: NSObject] = [:]

if let tempUserInfo = error.userInfo as? [NSObject: NSObject] {
  newUserInfo = tempUserInfo
}

2.

var newUserInfo: [NSObject: NSObject]

if let tempUserInfo = error.userInfo as? [NSObject: NSObject] {
  newUserInfo = tempUserInfo
} else {
  newUserInfo = [:]
}

3 Answers 3

7

As of Swift 1.2, you can now use let with deferred assignment so you can use your if/else version:

let newUserInfo: [NSObject: NSObject]

if let tempUserInfo = error.userInfo as? [NSObject: NSObject] {
  newUserInfo = tempUserInfo
} else {
  newUserInfo = [:]
}

However, option 1 will not work, since there is a path where newUserInfo may not be set.

(note, as of 1.2b1, this doesn't work with global variables, only member and local variables, in case you try this out in a playground)

Alternatively, you could use the nil-coalescing operator to do it in one go, like this:

let newUserInfo = (error.userInfo as? [NSObject:NSObject]) ?? [:]

edit: Swift 1.2 added deferred assignment of let, enabling option 2 to be used with let now, but also changed the precedence of as? vs ??, requiring parens.

Pre-1.2 answer in case you have similar code you need to migrate:

Neither are particularly appealing if you ask me. In both cases, you have to have to declare newUserInfo with var, because you're not declaring and assigning it in one go.

I'd suggest:

let newUserInfo = error.userInfo as? [NSObject:NSObject] ?? [:]
Sign up to request clarification or add additional context in comments.

2 Comments

Indeed - looks like the precedence of as? vs ?? has changed. Brackets fixes – let newUserInfo = (error.userInfo as? [NSObject:NSObject]) ?? [:], however there's also the new option of using let with the if/else, I'll update my answer.
2
  • In 1. newUserInfo is assigned twice if the if branch is executed. 2. is better in terms of performance
  • In 1. it's clearly visible that newUserInfo is initialized as an empty array. 2. makes the code less readable because you have to browse the code to know if it has a default value
  • If newUserInfo can be set in several places (such as if it can be initialized it in several if statements), you should duplicate the else branch in 2., so 1. looks better

So: in solution no. 1 code is more readable, but solution no. 2 is slightly more performant.

Besides using @AirspeedVelocity solution (which is better than yours, no offence :)), I'd rather prefer to use an optional, setting newUserInfo to nil to indicate absence of value - after all, that's what optionals are for, isn't it? But of course that depends on your specific needs.

Comments

0

My preferred pattern for this is:

struct TryUnrap<T> {
    typealias Tryee = () -> T?
    typealias Catchee = () -> T

    private var tryee: Tryee

    init(tryee: Tryee) {
        self.tryee = tryee
    }

    func catch(catchee: Catchee) -> T {
        if let result = tryee() {
            return result
        }
        return catchee()
    }
}

let error: NSError? = NSError()
let newUserInfo = TryUnrap {
    error?.userInfo as? [NSObject : NSObject]
}.catch {
    [:]
}
println("newUserInfo = \(newUserInfo)")

I prefer the above because I find it reads better for me. Also see answer 4 of Error-Handling in Swift-Language for general error handling using the same pattern.

3 Comments

This is essentially a non-idiomatic inefficient implementation of ?? for recovering Java programmers.
For me it looks more unreadable than the others, I prefer the first answers... but it's personal.
I don't find ?? very readable and it can't be used in other try catch situations either. However it is a matter of personal taste. The efficiency is almost certainly inconsequential, you are initialising a let which by definition is a one off.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.