bogen
bogen

Reputation: 10432

How to check for nil with nested convenience failable initializers in Swift?

class OAuthToken: NSObject, NSCoding {

var refreshToken: String?
var accessToken: String?
var scope: String?

convenience init?(refreshToken: String?, accessToken: String?, scope:String) {
    self.init()

    if let acutalRefreshToken = refreshToken as String? {
        self.refreshToken = acutalRefreshToken
    } else {
        return nil
    }
    if let actualAccessToken = accessToken as String? {
        self.accessToken = actualAccessToken
    }else {
        return nil
    }
    self.scope = scope
}

convenience init?(attributes: Dictionary<String,AnyObject>, scope: String) {
    var aRefreshToken: String!
    var anAccessToken: String?
    aRefreshToken = attributes["refresh_token"] as String?
    anAccessToken = attributes["access_token"] as String?
    let token = self.init(refreshToken: aRefreshToken, accessToken: anAccessToken, scope: scope) as OAuthToken // () is not convertible to OAuthToken
    if token != nil {
        storeInKeyChain()
    } else {
        return nil
    }
}
}

How do you check a failable initializer for nil when you call a nested failable initializer inside another?

the let token = self.init(refreshToken: aRefreshToken, accessToken: anAccessToken, scope: scope) wants to return an object of type (), not castable to my class. How can i use this pattern and only store the object to keychain if it was actually created successfully?

Upvotes: 8

Views: 890

Answers (2)

Antonio
Antonio

Reputation: 72760

I think that when you call a failable initializer of a superclass, it has an implicit return if it fails.

In fact the documentation about Failable Initializers states that:

If the superclass initialization fails because of an empty name value, the entire initialization process fails immediately and no further initialization code is executed

Upvotes: 8

Rob
Rob

Reputation: 437872

As Antonio says (+1), you don't have to test to see if the other initializer succeeded or not. If it failed, your current initialization fails immediately. For example, consider:

convenience init?(attributes: Dictionary<String,AnyObject>, scope: String) {
    let aRefreshToken = attributes["refresh_token"] as String?
    let anAccessToken = attributes["access_token"] as String?
    self.init(refreshToken: aRefreshToken, accessToken: anAccessToken, scope: scope)
    storeInKeyChain()
}

The storeInKeyChain() function is not called if init(refreshToken:, accessToken:, scope:) fails. See the Propagation of Initialization Failure section of The Swift Programming Language: Initialization.

Upvotes: 5

Related Questions