摆脱这些可选值

Get rid of these Optional values

使用 Xcode 7 测试版,Swift 2.0

我正在将凭据保存并加载到钥匙串,加载时不知何故我得到了 "Optional(value)",看起来这确实是字符串的一部分,因为它在文本框中或发送到时也显示为这样API

这就是我现在保存和加载凭据的方式,如您所见,我已经做了很多额外的 nil 检查以确保它不是 nil 或 Optional,这确实是对解释标记的过度使用...

func SaveCredentials(credentials : [String : String!]!) -> Bool
{
    if(credentials.count == 2)
    {
        //only proceed when we have two keys:  username and password
        let username = credentials["username"]
        let password = credentials["password"]

        if let usernameStr = username
        {//also tried username!=nil && password != nil
            if let passwordStr = password
            { //usernameStr and passwordStr is of type String!
                let NsDataUsername = usernameStr!.dataUsingEncoding(NSUTF8StringEncoding)
                let NsDataPassword = passwordStr!.dataUsingEncoding(NSUTF8StringEncoding)
                if(NsDataUsername != nil && NsDataPassword != nil)
                {
                    LocalStorage.saveToKeyChain("username", data: NsDataUsername!)
                    LocalStorage.saveToKeyChain("password", data: NsDataPassword!)
                    return true
                }
            }

        }
    }
    return false
}

func LoadCredentials() -> [String : String!]?
{
    let NsDataUsername = LocalStorage.loadFromKeyChain("username")
    let NsDataPassword = LocalStorage.loadFromKeyChain("password")
    if(NsDataUsername != nil && NsDataPassword != nil)
    {
        let username : String! = String(NSString(data: NsDataUsername!, encoding: NSUTF8StringEncoding))
        let password : String! = String(NSString(data: NsDataPassword!, encoding: NSUTF8StringEncoding))
        if let usernameStr = username
        {
            if let passwordStr = password
            { // password is of type String!, passwordStr is of type String
                var credentials : [String: String!] = [String : String]()
                credentials["username"] = usernameStr
                credentials["password"] = passwordStr
                return credentials
            }
        }
    }
    return nil
}

当我发送到 Api 时,这是我的方法,它也需要一个非可选字符串。此方法在登录时有效,从文本字段中获取字符串,但在来自钥匙串时不会过滤掉 Optional。

func LoginUser(email : String!, password : String!)
{
    print("LoginUser(email : \(email), password: \(password))")
    var parameters = [String : AnyObject]()
    parameters["UserName"] = email
    parameters["Password"] = password
   ......

我发送到 SaveCredentials 方法的字符串与用户登录时使用的字符串相同:

func LoginLocalAccount(email : String!, password : String!)
{
    databaseAPI.LoginUser(email!, password: password!) //login goes just fine
    saveCredentials(email!, password: password!) //manages to get Optional in it..
}

我怀疑和keychain的保存和加载有关,为了兴趣,this是我用来保存和从keychain加载的

我想摆脱它们,因为当应用程序启动时,它会加载凭据并尝试登录我的 API。当然,我得到一个错误,用户名不是有效的电子邮件,因为它是 Optional(email@adress.com)

您过度使用 !。你不需要它们。尝试了解更多关于隐式解包的可选值,可选值,......你的代码一团糟(没有冒犯,每个人都在学习)。

回到你的可选问题,它是由这一行引起的:

let username : String! = String(NSString(data: NsDataUsername!, encoding: NSUTF8StringEncoding))

convenience init?(data: NSData, encoding: UInt) - 内部使用可失败初始化器,因此,NSString? 是结果。然后用可选的 NSString? 初始化 String 也会产生可选的。但是,这样做完全没有意义。

第一部分 - 删除可选

利用新 guard:

guard let loadedPassword = NSString(data: passwordData, encoding: NSUTF8StringEncoding) else {
  fatalError("Ooops")
}

loadedPassword 现在包含 NSString(不是 NSString?)。

第二部分 - NSString -> String

你可能读过(如果没读过)Strings and Characters 关于桥接,...如果你可以自由地交换 NSStringString,你可以认为你是完成:

var dict = [String:String]()
dict["password"] = loadedPassword

没有。它产生以下错误:

NSString is not implicitly convertible to String; did you mean to use 'as' to explicitly convert?

稍微改变一下,现在你就完成了:

var dict = [String:String]()
dict["password"] = loadedPassword as String

完整示例

let password = "Hallo"
guard let passwordData = password.dataUsingEncoding(NSUTF8StringEncoding) else {
  fatalError("Ooops")
}

// save/load to/from keychain

guard let loadedPassword = NSString(data: passwordData, encoding: NSUTF8StringEncoding) else {
  fatalError("Ooops")
}

var dict = [String:String]()
dict["password"] = loadedPassword as String

print(dict) // "[password: Hallo]\n"