Evgenii Neumerzhitckii 10 лет назад
Родитель
Сommit
bbe8ffbfec
4 измененных файлов с 50 добавлено и 24 удалено
  1. 5 0
      CHANGELOG.md
  2. 19 12
      Distrib/KeychainSwiftDistrib.swift
  3. 19 12
      KeychainSwift/KeychainSwift.swift
  4. 7 0
      README.md

+ 5 - 0
CHANGELOG.md

@@ -0,0 +1,5 @@
+# KeychainSwift version history
+
+### 3.0.8
+
+Added `lastResultCode` property.

+ 19 - 12
Distrib/KeychainSwiftDistrib.swift

@@ -24,6 +24,9 @@ A collection of helper functions for saving text and data in the keychain.
 public class KeychainSwift {
 public class KeychainSwift {
   
   
   var lastQueryParameters: [String: NSObject]? // Used by the unit tests
   var lastQueryParameters: [String: NSObject]? // Used by the unit tests
+  
+  /// Contains result code from the last operation. Value is noErr (0) for a successful result.
+  public var lastResultCode: OSStatus = noErr
 
 
   var keyPrefix = "" // Can be useful in test.
   var keyPrefix = "" // Can be useful in test.
   
   
@@ -52,6 +55,8 @@ public class KeychainSwift {
   - parameter key: Key under which the text value is stored in the keychain.
   - parameter key: Key under which the text value is stored in the keychain.
   - parameter value: Text string to be written to the keychain.
   - parameter value: Text string to be written to the keychain.
   - parameter withAccess: Value that indicates when your app needs access to the text in the keychain item. By default the .AccessibleWhenUnlocked option is used that permits the data to be accessed only while the device is unlocked by the user.
   - parameter withAccess: Value that indicates when your app needs access to the text in the keychain item. By default the .AccessibleWhenUnlocked option is used that permits the data to be accessed only while the device is unlocked by the user.
+   
+   - returns: True if the text was successfully written to the keychain.
 
 
   */
   */
   public func set(value: String, forKey key: String,
   public func set(value: String, forKey key: String,
@@ -94,9 +99,9 @@ public class KeychainSwift {
     query = addAccessGroupWhenPresent(query)
     query = addAccessGroupWhenPresent(query)
     lastQueryParameters = query
     lastQueryParameters = query
     
     
-    let status: OSStatus = SecItemAdd(query as CFDictionaryRef, nil)
+    lastResultCode = SecItemAdd(query as CFDictionaryRef, nil)
     
     
-    return status == noErr
+    return lastResultCode == noErr
   }
   }
 
 
   /**
   /**
@@ -108,10 +113,12 @@ public class KeychainSwift {
   
   
   */
   */
   public func get(key: String) -> String? {
   public func get(key: String) -> String? {
-    if let data = getData(key),
-      let currentString = NSString(data: data, encoding: NSUTF8StringEncoding) as? String {
-
-      return currentString
+    if let data = getData(key) {
+      if let currentString = NSString(data: data, encoding: NSUTF8StringEncoding) as? String {
+        return currentString
+      }
+      
+      lastResultCode = -67853 // errSecInvalidEncoding
     }
     }
 
 
     return nil
     return nil
@@ -139,11 +146,11 @@ public class KeychainSwift {
     
     
     var result: AnyObject?
     var result: AnyObject?
     
     
-    let status = withUnsafeMutablePointer(&result) {
+    lastResultCode = withUnsafeMutablePointer(&result) {
       SecItemCopyMatching(query, UnsafeMutablePointer($0))
       SecItemCopyMatching(query, UnsafeMutablePointer($0))
     }
     }
     
     
-    if status == noErr { return result as? NSData }
+    if lastResultCode == noErr { return result as? NSData }
     
     
     return nil
     return nil
   }
   }
@@ -166,9 +173,9 @@ public class KeychainSwift {
     query = addAccessGroupWhenPresent(query)
     query = addAccessGroupWhenPresent(query)
     lastQueryParameters = query
     lastQueryParameters = query
     
     
-    let status: OSStatus = SecItemDelete(query as CFDictionaryRef)
+    lastResultCode = SecItemDelete(query as CFDictionaryRef)
     
     
-    return status == noErr
+    return lastResultCode == noErr
   }
   }
 
 
   /**
   /**
@@ -183,9 +190,9 @@ public class KeychainSwift {
     query = addAccessGroupWhenPresent(query)
     query = addAccessGroupWhenPresent(query)
     lastQueryParameters = query
     lastQueryParameters = query
     
     
-    let status: OSStatus = SecItemDelete(query as CFDictionaryRef)
+    lastResultCode = SecItemDelete(query as CFDictionaryRef)
     
     
-    return status == noErr
+    return lastResultCode == noErr
   }
   }
   
   
   /// Returns the key with currently set prefix.
   /// Returns the key with currently set prefix.

+ 19 - 12
KeychainSwift/KeychainSwift.swift

@@ -9,6 +9,9 @@ A collection of helper functions for saving text and data in the keychain.
 public class KeychainSwift {
 public class KeychainSwift {
   
   
   var lastQueryParameters: [String: NSObject]? // Used by the unit tests
   var lastQueryParameters: [String: NSObject]? // Used by the unit tests
+  
+  /// Contains result code from the last operation. Value is noErr (0) for a successful result.
+  public var lastResultCode: OSStatus = noErr
 
 
   var keyPrefix = "" // Can be useful in test.
   var keyPrefix = "" // Can be useful in test.
   
   
@@ -37,6 +40,8 @@ public class KeychainSwift {
   - parameter key: Key under which the text value is stored in the keychain.
   - parameter key: Key under which the text value is stored in the keychain.
   - parameter value: Text string to be written to the keychain.
   - parameter value: Text string to be written to the keychain.
   - parameter withAccess: Value that indicates when your app needs access to the text in the keychain item. By default the .AccessibleWhenUnlocked option is used that permits the data to be accessed only while the device is unlocked by the user.
   - parameter withAccess: Value that indicates when your app needs access to the text in the keychain item. By default the .AccessibleWhenUnlocked option is used that permits the data to be accessed only while the device is unlocked by the user.
+   
+   - returns: True if the text was successfully written to the keychain.
 
 
   */
   */
   public func set(value: String, forKey key: String,
   public func set(value: String, forKey key: String,
@@ -79,9 +84,9 @@ public class KeychainSwift {
     query = addAccessGroupWhenPresent(query)
     query = addAccessGroupWhenPresent(query)
     lastQueryParameters = query
     lastQueryParameters = query
     
     
-    let status: OSStatus = SecItemAdd(query as CFDictionaryRef, nil)
+    lastResultCode = SecItemAdd(query as CFDictionaryRef, nil)
     
     
-    return status == noErr
+    return lastResultCode == noErr
   }
   }
 
 
   /**
   /**
@@ -93,10 +98,12 @@ public class KeychainSwift {
   
   
   */
   */
   public func get(key: String) -> String? {
   public func get(key: String) -> String? {
-    if let data = getData(key),
-      let currentString = NSString(data: data, encoding: NSUTF8StringEncoding) as? String {
-
-      return currentString
+    if let data = getData(key) {
+      if let currentString = NSString(data: data, encoding: NSUTF8StringEncoding) as? String {
+        return currentString
+      }
+      
+      lastResultCode = -67853 // errSecInvalidEncoding
     }
     }
 
 
     return nil
     return nil
@@ -124,11 +131,11 @@ public class KeychainSwift {
     
     
     var result: AnyObject?
     var result: AnyObject?
     
     
-    let status = withUnsafeMutablePointer(&result) {
+    lastResultCode = withUnsafeMutablePointer(&result) {
       SecItemCopyMatching(query, UnsafeMutablePointer($0))
       SecItemCopyMatching(query, UnsafeMutablePointer($0))
     }
     }
     
     
-    if status == noErr { return result as? NSData }
+    if lastResultCode == noErr { return result as? NSData }
     
     
     return nil
     return nil
   }
   }
@@ -151,9 +158,9 @@ public class KeychainSwift {
     query = addAccessGroupWhenPresent(query)
     query = addAccessGroupWhenPresent(query)
     lastQueryParameters = query
     lastQueryParameters = query
     
     
-    let status: OSStatus = SecItemDelete(query as CFDictionaryRef)
+    lastResultCode = SecItemDelete(query as CFDictionaryRef)
     
     
-    return status == noErr
+    return lastResultCode == noErr
   }
   }
 
 
   /**
   /**
@@ -168,9 +175,9 @@ public class KeychainSwift {
     query = addAccessGroupWhenPresent(query)
     query = addAccessGroupWhenPresent(query)
     lastQueryParameters = query
     lastQueryParameters = query
     
     
-    let status: OSStatus = SecItemDelete(query as CFDictionaryRef)
+    lastResultCode = SecItemDelete(query as CFDictionaryRef)
     
     
-    return status == noErr
+    return lastResultCode == noErr
   }
   }
   
   
   /// Returns the key with currently set prefix.
   /// Returns the key with currently set prefix.

+ 7 - 0
README.md

@@ -134,6 +134,13 @@ if keychain.set("hello world", forKey: "my key") {
 }
 }
 ```
 ```
 
 
+To get a specific failure reason use the `lastResultCode` property containing result code for the last operation. Its valus is noErr (0) for success. See [Keychain Services Result Codes](https://developer.apple.com/library/mac/documentation/Security/Reference/keychainservices/#//apple_ref/doc/uid/TP30000898-CH5g-CJBEABHG).
+
+```Swift
+keychain.set("hello world", forKey: "my key")
+if keychain.lastResultCode != noErr { /* Report error */ }
+```
+
 ## Demo app
 ## Demo app
 
 
 <img src="https://raw.githubusercontent.com/exchangegroup/keychain-swift/master/graphics/keychain-swift-demo.png" alt="Sacing and reading text from Keychaing in iOS and Swift" width="320">
 <img src="https://raw.githubusercontent.com/exchangegroup/keychain-swift/master/graphics/keychain-swift-demo.png" alt="Sacing and reading text from Keychaing in iOS and Swift" width="320">