KeychainWrapper保存数据并在同一函数中检索它不起作用

时间:2016-10-24 16:15:47

标签: ios swift keychain

所以我有一个自定义函数,它向我的网络服务器发出HTTP POST请求以从我的数据库中获取一些字段,然后将其返回到我的iOS应用程序,该应用程序将使用KeychainWrapper将该字段值保存为钥匙串项。

我的iOS应用程序就像登录屏幕一样简单,它会再次使用HTTP POST检查mySQL数据库中的用户凭据是否正确,如果正确,则会将我带到一个用户页面,在该页面中应该显示使用KeychainWrapper抓取并显示的一些信息。

现在我遇到的问题是每当我按下登录页面上的登录按钮并登陆用户页面时,所有字段都显示为空。但是如果我停止构建并重新构建,它将加载回该页面,这次加载了字段。 好像当我第一次进入用户页面时,这些字段还没有保存在钥匙串中,但是当我重建它时,它们就是从那里加载的。

我会从我的代码中删除一些部分,使其缩短并使其与此问题保持相关。这是我的函数,它从MYSQL数据库请求元字段:

func requestMetaField(metaField:String) -> String {

        let userEmail: String = KeychainWrapper.standard.string(forKey: "email")!;
        let userPassword: String = KeychainWrapper.standard.string(forKey: "password")!;
        let meta = metaField;

        // Send data to server side
        // Classic HTTP POST Request using JSONSerialization here.

                    if(resultValue=="Success") {

                        // Save downloaded data to keychain
                        self.saveDataToKeychain(value: metaValue, key: meta);
                    }

        // End of the HTTP POST Request and else statements.

        if let metaValue: String = KeychainWrapper.standard.string(forKey: meta) {
        return metaValue;
        } else {
            return "N/A";
        }

    }

这是我的saveDataToKeychain函数:

func saveDataToKeychain(value:String, key:String) -> Bool {
        let saveSuccessful: Bool = KeychainWrapper.standard.set(value, forKey: key);
        return saveSuccessful;
    }

这是我在用户页面上使用该功能将其应用于标签的地方:

override func viewDidLoad() {
        super.viewDidLoad()

        logoutButton.layer.cornerRadius = 6;

        let firstName = requestMetaField(metaField: "first_name");
        let lastName = requestMetaField(metaField: "last_name");
        userFullName.text = "\(firstName) \(lastName)";

        let userMinuteBalance = requestMetaField(metaField: "mycred_default_total");
        userBalance.text = "\(userMinuteBalance) min";
    }

这是我保存电子邮件的地方。使用登录按钮时钥匙串中的密码:

if(resultValue=="Success") {

                        // Login is successful
                        UserDefaults.standard.set(true, forKey: "isUserLoggedIn");
                        UserDefaults.standard.synchronize();

                        // Save email & password in keychain
                        self.saveDataToKeychain(value: userEmail!, key: "email");
                        self.saveDataToKeychain(value: userPassword!, key: "password");

                        isUserLoggedIn = true;
}

有没有人知道我在登录时如何立即访问数据?

此外,我使用了Keychain方法,因为我已经读过它是最安全的用户信息之一,但是如果有人认为比使用钥匙串更容易做到这一点,我会接受其他选项。< / p>

非常感谢您提供任何帮助!!

1 个答案:

答案 0 :(得分:0)

我认为问题是你将requestMetaField视为同步函数,当它是异步时。在requestMetaField返回后的某个时间,您的HTTP请求将无法完成。

另一种方法是编写requestMetaField版本,该版本采用在请求完成时调用的回调函数。然后,您可以从回调更新UI。

这就是requestMetaField的样子:

func requestMetaField(metaField:String, callback: @escaping (String) -> Void) {

        let userEmail: String = KeychainWrapper.standard.string(forKey: "email")!;
        let userPassword: String = KeychainWrapper.standard.string(forKey: "password")!;
        let meta = metaField;

        // Send data to server side
        // Classic HTTP POST Request using JSONSerialization here.

                    if(resultValue=="Success") {

                        // Save downloaded data to keychain
                        self.saveDataToKeychain(value: metaValue, key: meta);

                        // call callback with value
                        callback(metaValue)
                    }

viewDidLoad中的代码如下所示:

    requestMetaField(metaField: "first_name") { firstName in 
        requestMetaField(metaField: "last_name") { lastName in
            DispatchQueue.main.async {        
                userFullName.text = "\(firstName) \(lastName)"
            }
        }
    }

    requestMetaField(metaField: "mycred_default_total") { userMinuteBalance in
        DispatchQueue.main.async {        
            userBalance.text = "\(userMinuteBalance) min"
        }
    }