Swift variable value

What's the difference between these two ads? 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


source to share


3 answers


As of Swift 1.2, you can use let

deferred assignment so that 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 as there is a path that newUserInfo

cannot be set.

(note that as of 1.2b1 this does not work with globals, only member and local variables if you try this in a playground)

Alternatively, you can use the nil-coalescing operator to do this in one go, e.g .:

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

      




edit: Swift 1.2 adds deferred assignment let

, now includes 2s option let

, but also changed the priority of as?

vs ??

, requiring parens.

Pre-1.2 answer if you have similar code that you need to port:

None of them are particularly appealing if you ask me. In both cases, you need to declare newUserInfo

using var

, because you are not declaring or assigning it in one go.

I would suggest:

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

      

+7


source


  • In newUserInfo

    1.assigned twice if branch is executed if

    . 2.better in terms of performance
  • In 1. it is clear that it is newUserInfo

    initialized as an empty array. 2.makes the code less readable because you need to look at the code to see if the default is
  • If newUserInfo

    it is possible to install in multiple locations (for example if it can be initialized in multiple operations if

    ) then you should duplicate the branch else

    in 2., so 1. looks better

So: not in the solution. 1 code is more readable, but no solution. 2 is slightly more effective.



Apart from using @AirspeedVelocity's solution (which is better than yours, no offense :)), I prefer to use optional , setting newUserInfo

to nil to indicate no value - after all, what are these options, right? But of course it depends on your specific needs.

+2


source


My preferred template for this:

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 think it is best for me. Also see Answer 4 Error Handling in Swift-Language for general error handling using the same pattern.

0


source







All Articles