I\'m trying to add an item to the iOS keychain using Swift but can\'t figure out how to type cast properly. From WWDC 2013 session 709, given the following Objective-C code:
This seemed to work fine or at least compiler didn't have kittens - UNTESTED beyond that
var secret: NSData = "Top Secret".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
var array1 = NSArray(objects:"\(kSecClassGenericPassword)", "MyService", "Some account", secret)
var array2 = NSArray(objects:"\(kSecClass)","\(kSecAttrService)", "\(kSecAttrAccount)","\(kSecValueData)")
let query = NSDictionary(objects: array1, forKeys: array2)
println(query)
let status = SecItemAdd(query as CFDictionaryRef, nil)
Seems to work fine in Beta 2
Swift 3
let kSecClassKey = String(kSecClass)
let kSecAttrAccountKey = String(kSecAttrAccount)
let kSecValueDataKey = String(kSecValueData)
let kSecClassGenericPasswordKey = String(kSecClassGenericPassword)
let kSecAttrServiceKey = String(kSecAttrService)
let kSecMatchLimitKey = String(kSecMatchLimit)
let kSecReturnDataKey = String(kSecReturnData)
let kSecMatchLimitOneKey = String(kSecMatchLimitOne)
you can also do it inside the dictionary itself alá:
var query: [String: Any] = [
String(kSecClass): kSecClassGenericPassword,
String(kSecAttrService): "MyService",
String(kSecAttrAccount): "Some account",
String(kSecValueData): secret
]
however, this is more expensive for the compiler, even more so since you're probably using the query in multiple places.
In the xcode 6.0.1 you must do this!!
let kSecClassValue = NSString(format: kSecClass)
let kSecAttrAccountValue = NSString(format: kSecAttrAccount)
let kSecValueDataValue = NSString(format: kSecValueData)
let kSecClassGenericPasswordValue = NSString(format: kSecClassGenericPassword)
let kSecAttrServiceValue = NSString(format: kSecAttrService)
let kSecMatchLimitValue = NSString(format: kSecMatchLimit)
let kSecReturnDataValue = NSString(format: kSecReturnData)
let kSecMatchLimitOneValue = NSString(format: kSecMatchLimitOne)
You simply need to downcast the literal:
let dict = ["hi": "Pasan"] as NSDictionary
Now dict
is an NSDictionary. To make a mutable one, it's very similar to Objective-C:
let mDict = dict.mutableCopy() as NSMutableDictionary
mDict["hola"] = "Ben"
In order to get this to work, you need to access the retained values of the keychain constants instead. For example:
let kSecClassValue = kSecClass.takeRetainedValue() as NSString
let kSecAttrAccountValue = kSecAttrAccount.takeRetainedValue() as NSString
let kSecValueDataValue = kSecValueData.takeRetainedValue() as NSString
let kSecClassGenericPasswordValue = kSecClassGenericPassword.takeRetainedValue() as NSString
let kSecAttrServiceValue = kSecAttrService.takeRetainedValue() as NSString
let kSecMatchLimitValue = kSecMatchLimit.takeRetainedValue() as NSString
let kSecReturnDataValue = kSecReturnData.takeRetainedValue() as NSString
let kSecMatchLimitOneValue = kSecMatchLimitOne.takeRetainedValue() as NSString
You can then reference the values in the MSMutableDictionary like so:
var keychainQuery: NSMutableDictionary = NSMutableDictionary(objects: [kSecClassGenericPasswordValue, service, userAccount, kCFBooleanTrue, kSecMatchLimitOneValue], forKeys: [kSecClassValue, kSecAttrServiceValue, kSecAttrAccountValue, kSecReturnDataValue, kSecMatchLimitValue])
I wrote a blog post about it at: http://rshelby.com/2014/08/using-swift-to-save-and-query-ios-keychain-in-xcode-beta-4/
Hope this helps!
rshelby
more convenient to use the cocoa pods SSKeychain
+ (NSArray *)allAccounts;
+ (NSArray *)accountsForService:(NSString *)serviceName;
+ (NSString *)passwordForService:(NSString *)serviceName account:(NSString *)account;
+ (BOOL)deletePasswordForService:(NSString *)serviceName account:(NSString *)account;
+ (BOOL)setPassword:(NSString *)password forService:(NSString *)serviceName account:(NSString *)account;