Keychain Add Update Remove and Find operations using one file.

suggest change

Keychain.h

#import <Foundation/Foundation.h>
typedef void (^KeychainOperationBlock)(BOOL successfulOperation, NSData *data, OSStatus status);

@interface Keychain : NSObject

-(id) initWithService:(NSString *) service_ withGroup:(NSString*)group_;

-(void)insertKey:(NSString *)key withData:(NSData *)data withCompletion:(KeychainOperationBlock)completionBlock;
-(void)updateKey:(NSString*)key withData:(NSData*) data withCompletion:(KeychainOperationBlock)completionBlock;
-(void)removeDataForKey:(NSString*)key withCompletionBlock:(KeychainOperationBlock)completionBlock;
-(void)findDataForKey:(NSString*)key withCompletionBlock:(KeychainOperationBlock)completionBlock;

@end

Keychain.m

#import "Keychain.h"
#import <Security/Security.h>

@implementation Keychain

{
   NSString * keychainService;
   NSString * keychainGroup;
}

-(id) initWithService:(NSString *)service withGroup:(NSString*)group
{
   self =[super init];
   if(self) {
       keychainService = [NSString stringWithString:service];
       if(group) {
           keychainGroup = [NSString stringWithString:group];
       }
   }
   
   return  self;
}

-(void)insertKey:(NSString *)key
       withData:(NSData *)data
 withCompletion:(KeychainOperationBlock)completionBlock
{
   NSMutableDictionary * dict =[self prepareDict:key];
   [dict setObject:data forKey:(__bridge id)kSecValueData];
   [dict setObject:keychainService forKey:(id)kSecAttrService];
   
   OSStatus status = SecItemAdd((__bridge CFDictionaryRef)dict, NULL);
   if(errSecSuccess != status) {
       DLog(@"Unable add item with key =%@ error:%d",key,(int)status);
       if (completionBlock) {
           completionBlock(errSecSuccess == status, nil, status);
       }
   }
   if (status == errSecDuplicateItem) {
       [self updateKey:key withData:data withCompletion:^(BOOL successfulOperation, NSData *updateData, OSStatus updateStatus) {
           if (completionBlock) {
               completionBlock(successfulOperation, updateData, updateStatus);
           }
           DLog(@"Found duplication item -- updating key with data");
       }];
   }
}

-(void)findDataForKey:(NSString *)key
 withCompletionBlock:(KeychainOperationBlock)completionBlock
{
   NSMutableDictionary *dict = [self prepareDict:key];
   [dict setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit];
   [dict setObject:keychainService forKey:(id)kSecAttrService];
   [dict setObject:(id)kCFBooleanTrue forKey:(__bridge id)kSecReturnData];
   CFTypeRef result = NULL;
   OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)dict,&result);
   
   if( status != errSecSuccess) {
       DLog(@"Unable to fetch item for key %@ with error:%d",key,(int)status);
       if (completionBlock) {
           completionBlock(errSecSuccess == status, nil, status);
       }
   } else {
       if (completionBlock) {
           completionBlock(errSecSuccess == status, (__bridge NSData *)result, status);
       }
   }
}

-(void)updateKey:(NSString *)key
       withData:(NSData *)data
 withCompletion:(KeychainOperationBlock)completionBlock
{
   NSMutableDictionary * dictKey =[self prepareDict:key];
   
   NSMutableDictionary * dictUpdate =[[NSMutableDictionary alloc] init];
   [dictUpdate setObject:data forKey:(__bridge id)kSecValueData];
   [dictUpdate setObject:keychainService forKey:(id)kSecAttrService];
   OSStatus status = SecItemUpdate((__bridge CFDictionaryRef)dictKey, (__bridge CFDictionaryRef)dictUpdate);
   if( status != errSecSuccess) {
       DLog(@"Unable to remove item for key %@ with error:%d",key,(int)status);
   }
   if (completionBlock) {
       completionBlock(errSecSuccess == status, nil, status);
   }
}

-(void)removeDataForKey:(NSString *)key
   withCompletionBlock:(KeychainOperationBlock)completionBlock {
   NSMutableDictionary *dict = [self prepareDict:key];
   OSStatus status = SecItemDelete((__bridge CFDictionaryRef)dict);
   if( status != errSecSuccess) {
       DLog(@"Unable to remove item for key %@ with error:%d",key,(int)status);
   }
   if (completionBlock) {
       completionBlock(errSecSuccess == status, nil, status);
   }
}

#pragma mark Internal methods

-(NSMutableDictionary*) prepareDict:(NSString *) key {
   
   NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
   [dict setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
   
   NSData *encodedKey = [key dataUsingEncoding:NSUTF8StringEncoding];
   [dict setObject:encodedKey forKey:(__bridge id)kSecAttrGeneric];
   [dict setObject:encodedKey forKey:(__bridge id)kSecAttrAccount];
   [dict setObject:keychainService forKey:(__bridge id)kSecAttrService];
   [dict setObject:(__bridge id)kSecAttrAccessibleAlwaysThisDeviceOnly forKey:(__bridge id)kSecAttrAccessible];
   
   //This is for sharing data across apps
   if(keychainGroup != nil) {
       [dict setObject:keychainGroup forKey:(__bridge id)kSecAttrAccessGroup];
   }
   
   return  dict;
}

@end

Feedback about page:

Feedback:
Optional: your email if you want me to get back to you:


Keychain:
* Keychain Add Update Remove and Find operations using one file.

Table Of Contents
12 UIView
15 UIColor
26 UIImage
28 CALayer
30 NSDate
40 iBeacon
49 NSTimer
79 NSURL
87 AWS SDK
96 NSData
101 Segues
104 EventKit
105 NSBundle
106 SiriKit
111 StoreKit
117 3D Touch
119 Keychain
122 Block
141 AirDrop
144 UISlider
145 Carthage
146 HealthKit
151 plist
157 MVVM
164 UIPhoenix
166 Simulator
168 NSArray
169 OpenGL
175 Core Data
179 MyLayout
180 UIFont
189 Security
200 Codable