廣告
Swift iOS開發小書 ,幫你快速上手開發 www.ituring.com.cn/book/2413
正文
KeyChain提供了加密儲存敏感資訊的方法。所謂的敏感資訊,不外是密碼,信用卡號等。如果一個物件含有敏感資訊,也可以把整個物件序列化為Data,然後整體存入KeyChain。對應的,也有從KeyChain中提取Data出來的操作。
然而,KeyChain預設提供的API是相當冗長和囉嗦的。而使用一些第三方庫如KeyChainSwift又顯得過於重量級。這裡對KeyChain做了一個簡單的封裝,並提供了一個案例,可以把一個物件(User)儲存到KeyChain內,並反向操作列印進入和出來的物件的結果。
物件是需要符合NSCoding協議的,以便可以序列化為Data物件,以及從Data物件內回覆一個物件出來。程式碼改編於 gist.github.com/s-aska/e7ad…
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let user = User(1,"tom")
user.saveToKC()
let user1 = User.loadFromKC()
print(user,user1)
return true
}
}
class User : NSObject,NSCoding{
var id : Int32
var name : String
init(_ id: Int32 ,_ name : String) {
self.id = id
self.name = name
}
required convenience init?(coder decoder: NSCoder) {
guard let id = decoder.decodeInt32(forKey: "id") as? Int32,
let name = decoder.decodeObject(forKey:"name") as? String
else { return nil }
self.init(id,name)
}
func encode(with coder: NSCoder) {
coder.encode(self.id, forKey: "id")
coder.encode(self.name, forKey: "name")
}
override public var description: String { return "{id:\(id),name:\(name)}" }
func saveToKC(){
let data = NSKeyedArchiver.archivedData(withRootObject: self)
_ = Keychain.save(key: "user", data: data)
}
class func loadFromKC()-> User{
let data = Keychain.load(key: "user")
return NSKeyedUnarchiver.unarchiveObject(with: data!) as! User
}
}
import UIKit
import Security
class Keychain {
class func save(key: String, data: Data) -> Bool {
let query = [
kSecClass as String : kSecClassGenericPassword as String,
kSecAttrAccount as String : key,
kSecValueData as String : data ] as [String : Any]
SecItemDelete(query as CFDictionary)
let status: OSStatus = SecItemAdd(query as CFDictionary, nil)
return status == noErr
}
class func load(key: String) -> Data? {
let query = [
kSecClass as String : kSecClassGenericPassword,
kSecAttrAccount as String : key,
kSecReturnData as String : kCFBooleanTrue,
kSecMatchLimit as String : kSecMatchLimitOne ] as [String : Any]
var dataTypeRef: AnyObject?
let status = withUnsafeMutablePointer(to: &dataTypeRef) { SecItemCopyMatching(query as CFDictionary, UnsafeMutablePointer($0)) }
if status == errSecSuccess {
if let data = dataTypeRef as! Data? {
return data
}
}
return nil
}
class func delete(key: String) -> Bool {
let query = [
kSecClass as String : kSecClassGenericPassword,
kSecAttrAccount as String : key ] as [String : Any]
let status: OSStatus = SecItemDelete(query as CFDictionary)
return status == noErr
}
class func clear() -> Bool {
let query = [ kSecClass as String : kSecClassGenericPassword ]
let status: OSStatus = SecItemDelete(query as CFDictionary)
return status == noErr
}
}複製程式碼
執行後,應該可以看到控制檯上列印:
{id:1,name:tom} {id:1,name:tom}複製程式碼