1

I have to store an NSArray (which contains NSString and BOOL) into a KeychainItemWrapper to re use it in another ViewController, and to keep it in memory even if the app is closed.

I've already see at this question but it won't help me, because I can't find the SBJsonWriter files.

Can anyone could help me please ?

Thanks a lots.

Have a good day !

Community
  • 1
  • 1
ben77650
  • 39
  • 8
  • Does the string contain sensitive information? – trojanfoe Jul 02 '14 at 13:09
  • How NSArray can store BOOL? – gran33 Jul 02 '14 at 13:12
  • 2
    Why do you want to save it in the keychain? Is it highly confidential? – jailani Jul 02 '14 at 13:13
  • @gran33 [NSNumber numberWithBool:YES], or simply @(YES) (NSNumber wrapped bool) – SomeGuy Jul 02 '14 at 13:14
  • @SomeGuy [NSNumber numberWithBool:YES] is not BOOL, I think it's NSNumber no?! :) – gran33 Jul 02 '14 at 13:15
  • @gran33 technically it is an NSNumber, but it's the only way to put primitive types into an NSArray or NSDictionary, it will also be serialized to {"key":true} in JSON – SomeGuy Jul 02 '14 at 13:18
  • The only sensitive informations are phone number and email adress, others infos aren't so sensitive (title, imagePath, date, price, city, category, zipCode, username, description, id, onLine status, phone_hidding). Yeah SomeGuy i used @YES or NO for my bool – ben77650 Jul 02 '14 at 13:25

2 Answers2

1

SBJsonWriter is a 3rd party JSON library popular years back, now iOS has this built in.

Serialize the data as JSON using the native NSJSONSerialization, and then write it to the keychain (assuming kSecValueData, which is encrypted):

NSArray* array = ...;

NSData* jsonData = [NSJSONSerialization dataWithJSONObject:array options:0 error:nil];
NSString* jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];

[keychainItem setObject:jsonString forKey:(__bridge id)kSecValueData];

To read the data back to an NSArray:

NSString* jsonString = [keychainItem objectForKey:(__bridge id)kSecValueData];
NSArray* array = nil;

if(jsonString.length > 0)
{
    id jsonObject = [NSJSONSerialization JSONObjectWithData:[jsonString dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil];

    //  Type check because the JSON serializer can return an array or dictionary
    if([jsonObject isKindOfClass:[NSArray class]])
        array = jsonObject;
}

//  use your array variable here, it may be nil
SomeGuy
  • 9,670
  • 3
  • 32
  • 35
  • Is it possible to add some data in the array I pass in my KeychainItem ? I have to manage a system of favorite offers (it's a small ads app), and these info are store as a Array. I want to add it when user hit the button "Add favorite" and delete it when the user just tap into "Delete favorite" button. I hope you can understand me. Thanks a lot – ben77650 Jul 02 '14 at 13:31
  • In fact i want to store a NSArray who contains NSArray, do you think it's possible please ? – ben77650 Jul 02 '14 at 13:38
  • @ben77650 in the NSArray you can add primitive types wrapped in an NSNumber, NSStrings, NSArrays and NSDictionaries (including nested) - these types are compatible for serialization into a JSON string. However, from your explanation the favorite offers data doesn't sound like it is sensitive, so possibly doesn't need to be encrypted securely in the keychain. Remember the keychain is for small bits of sensitive information, it sounds like you need a database or a .json/.plist file saved to disk. If you need a complex set of data, I recommend a database. – SomeGuy Jul 02 '14 at 13:40
  • the first thing i thought is to add a property of type BOOL to database with name "isFavorite", but my boss doesn't want to apply this method because my colleague who is an Android developer, has succeed to manage favorite offers without store informations in the database. The informations about my small ads, is a NSArray of 16 items (including 14 NSString, 1 BOOL and 1 NSArray) – ben77650 Jul 02 '14 at 13:46
  • @ben77650 in the past I have stored 'favorites' to a plist without a database, but I only saved an NSArray of integer ids, then I would read them into an NSSet stored in memory (to prevent needing to query the db everytime), and check whether it's favorited with [set containsObject:@(id)]. If you are also including cached information about the favorite such as phone, title, email, description then this information will add up as the user favorites many objects, and if it's in a single dump file you will need to read everything into memory, even if you want to get just one object. – SomeGuy Jul 02 '14 at 13:52
  • I have to store a NSArray of NSArray, because if I only store id of the small ads I have to make a request in a webservice that find the object with the id, and my boss doesn't want a new webservice too. – ben77650 Jul 02 '14 at 14:00
  • How it goes if I already have attributes with name kSecAttrAccount and kSecValueData please ? How the difference it's possible between 2 var which are of type kSecAttrAccount ? – ben77650 Jul 02 '14 at 14:47
  • @ben77650 In a normal situation, kSecAttrAccount holds the username (not encrypted) and kSecValueData holds the password (encrypted). If you need to store more than one you can set a custom identifier per keychain item. – SomeGuy Jul 02 '14 at 14:59
  • In fact I already store username and password in these attributes. I also got a kSecValuePersistentRef in my SecItem.h but I don't know what it is, and i can't edit the file in my xCode, to add a new custom identifier. – ben77650 Jul 02 '14 at 15:07
  • "Could not add write permission to the file because you do not own it. Try modifying the permissions of the file in the Finder or Terminal." – ben77650 Jul 02 '14 at 15:10
  • ok I succeed to edit my SecItem.h, and add a new custom identifier. You don't answer to my question right above: "Is it possible to add some data in the array I pass in my KeychainItem ? I have to manage a system of favorite offers (it's a small ads app), and these info are store as a Array. I want to add it when user hit the button "Add favorite" and delete it when the user just tap into "Delete favorite" button. I hope you can understand me. Thanks a lot " – ben77650 Jul 02 '14 at 15:37
0

You can use Apple's NSJSONSerialization class to do what your linked answer is using SBJsonWriter to do.

Example:

NSData* jsonData = [NSJSONSerialization dataWithJSONObject:myArray options:0 error:&error];
NSString* jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];

Then write the jsonString to your keychain.

To reverse the process, retrieve the jsonString from your keychain and do this:

NSArray* myArray = [NSJSONSerialization JSONObjectWithData:jsonString options:0 error:&error];
Sandy Chapman
  • 11,133
  • 3
  • 58
  • 67