Can we set data from a plist to Keychain in iOS? - ios

Can we set data from a plist to Keychain in iOS? If we can do what is the correct approach. Also please let me know if there is any regular tutorial on the same.

Why do you want to save the data in keychain? probably because it is safe. Then you can use NSKeyedArchiver to save the encoded the plist data.
to store the encoded data in plist:
[NSKeyedArchiver archiveRootObject:data toFile:dataPath];
For your questions to get the data from plist file:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths firstObject];
NSString *dataPath = [documentsDirectory stringByAppendingPathComponent:#"filename.plist"];
ObjectClassName *fetchedObject = [NSKeyedUnarchiver unarchiveObjectWithFile:dataPath];
to store the data in keychain:
[UICKeyChainStore setString:userPassword forKey:keychainKeyUserPassword];

Related

How to read a file without extension in Objective C

I have a file stored in my iOS App Documents directory. It is a plist file but without .plist file extension. I want to read its content from code but i cant open the file without extension. Is there any way to add plist extension or convert the file into plist, or any way to read content of a file without extension.
This is how my code look like
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:#"sample.bookmarks"];
filePath = [filePath stringByAppendingPathExtension:#"plist"];
NSDictionary *dict=[NSDictionary dictionaryWithContentsOfFile:filePath];
Thanks in Advance
PS : If I add the .plist extension in finder(by some method) I can open the file and see the content. So I am sure about its type.
It should be possible to load the Plist file whether it has a .plist extension or not. Assuming the Plist filename is sample.bookmarks then the following should load the Plist. I am assuming the root element of the Plist is a dictionary because you state that the Plist can be opened if it has a .plist extension.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:#"sample.bookmarks"];
NSDictionary *dict=[NSDictionary dictionaryWithContentsOfFile:filePath];
The only change is that I've removed the line that adds a plist extension to the filePath.
The filePath = [filePath stringByAppendingPathExtension:#"plist"]; line will change the filename portion of the filePath to sample.bookmarks.plist. If you changed the extension to an empty string (filePath = [filePath stringByAppendingPathExtension:#""];) then the filename will be changed to sample.bookmarks. which is not the same as sample.bookmarks.
Try with this.
pathToFile = [pathToFile stringByAppendingPathExtension:#"plist"];

How to save 2 NSMutableDictionary on disk

The development is in Xcode for iOS. I used 2 separate NSmutabledictionary.
I DON´T want to add them (when searching I found that often, but that is not what I try to do)
The app has to store them on the disk and when the app launches it can read the dictionary.
It is not a custom class so initWithCoder and the other one is not necessary (is this right?)
NSArray *data = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *path = [data objectAtIndex:0];
path = [path stringByAppendingPathComponent:#"location"];
[NSKeyedArchiver archiveRootObject:"Dictionary" toFile:path];
This works but when I want to save another dictionary it won't work. My first thought would be to change the objectAtIndex to 1. But Xcode gives me an error when I do that. When I only give another name it simply won't save, but Xcode don't give an error.
What am I doing wrong?
// Find out where the documents folder is
NSString *documentsDirectory = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
// Create the file path for a file named 'location' inside the documents folder
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"location"];
// Write an array containing both of your arrays to a file at that path
[NSKeyedArchiver archiveRootObject:#[myFirstArray, mySecondArray] toFile:path];
Then, to read them back:
// Read back the array containing the two arrays
NSArray *arrays = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
// Get the individual arrays from the array
NSMutableArray *myFirstArray = arrays[0];
NSMutableArray *mySecondArray = arrays[1];

Read and Write the MetaData contents as a File in Documents Directory

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString* arrayText = [MetaDataArray componentsJoinedByString: #"\n"];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"EmployeeData.txt"];
[arrayText writeToFile:path atomically:YES];
MetaData Array first Object look like this :
{fileSize:"9385033" labels:{viewed,starred,restricted,trashed,hidden}
originalFilename:"Chamak Challo - Ra.One (2011) [MP3-320Kbps-CBR].mp3" mimeType:"audio/mpeg"
title:"Chamak Challo - Ra.One (2011) [MP3-320Kbps-CBR].mp3" parents:[1]
md5Checksum:"51d598c750102dd4bca09addf4d8212d" quotaBytesUsed:"9385033"
lastModifyingUserName:"shadow.hibrise" copyable?:1
headRevisionId?:"0B7v4X9XjauwJR3dZM1FQWlpHeEFOZGYyYzR2NUdtLzhmb2FNPQ" kind:"drive#file"
writersCanShare:1 appDataContents?:0 modifiedDate:"2014-03-04T11:13:32.649Z" shared?:0
id:"0B7v4X9XjauwJdTUyeW5zTVRNTU0" ownerNames:[1] userPermission:{etag,kind,id,type,role}
createdDate:"2014-03-04T11:13:32.649Z" fileExtension:"mp3"
iconLink?:"https://ssl.gstatic.com/docs/doclist/images/icon_10_audio_list.png"
modifiedByMeDate:"2014-03-04T11:13:32.634Z" downloadUrl:"https://doc-10-3s-
docs.googleusercontent.com/docs/securesc/0ijvatgpdej0qafpk7qtp7n2jgndtb3d/ifb42us5ai6ae9ah4kalfu4cnrtl6j3n/1398153600000/18240796891762319987/18240796891762319987/0B7v4X9XjauwJdTUyeW5zTVRNTU0?h=16653014193614665626&e=download&gd=true" lastModifyingUser?:{kind,displayName,permissionId,isAuthenticatedUser} editable:1 etag:""fgLq6vWOgR-hiHy-psxfsLtIDgQ/MTM5MzkzMTYxMjY0OQ"" webContentLink:"https://docs.google.com/uc?id=0B7v4X9XjauwJdTUyeW5zTVRNTU0&export=download" owners?:[1] alternateLink:"https://docs.google.com/file/d/0B7v4X9XjauwJdTUyeW5zTVRNTU0/edit?
usp=drivesdk"}
I want to store Array of Objects as a file and vice versa.
You can use Sqllite or core data instead of filesystem.
For core-data please refer this link
For filesystem this can be useful

How to load app with local data and subsequently update it when online.

Right now I have an app that successfully parses JSON from my website. So whenever there is no internet connection, my app crashes. Now I am trying to make it so that when the app is loaded with no internet connection, it will show the data that was shown previously. What would be the best way to do this?
I read this article but I don't know how to embed a JSON file into my app bundle. Could someone explain how to do this?
Thanks in advance!
The best way is:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"YourParsedJSON.plist"];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (noInternet){
if ([fileManager fileExistsAtPath: path]){
// if this is true, you have a saved version of your JSON
YourArray = [[NSMutableArray alloc] initWithContentsOfFile: path];
// or
YourDict = [[NSMutableArray alloc] initWithContentsOfFile: path];
}
else{
// first time the app is running, and no internet, no json, inform user about this
}
}
else{
// make an array or dictionary ( what is your JSON )
// response can be a NSDictionary or NSArray
// YourArray = parsedJSON or YourDict = parsedJSON
[YourArray writeToFile:path atomically:YES];
//or
[YourDictionary writeToFile:path atomically:YES];
}
I hope it helps !
Use Apple Reachability sample code to check if your app is able to establish connection to your server.
On first successful request-response, parse the JSON and cache it to disk as a .plist file. This will save you parsing the stored response again. A parsed JSON response can be a NSDictionary or NSArray. Use the writeToFile:atomically: API to write it to disk.
On subsequent request, if reachability fails, i.e. no network connectivity, read the cached response from disk. You need to decide the cache duration and update the plist when a fresh response is fetched.
Hope that helps!
EDIT:
I think I did not understand the question completely. Thanks Xman, for pointing it out. What I would have done in this case is - save the last loaded JSON file to my bundle and use it for displaying information while querying the server and loading updates in the background.
The flow should be like this:
Parse and display data using local JSON file. (Assuming there is local copy of JSON file)
Query the server for latest data.
Upon receiving response, update the bundle with the latest JSON file.
Then, do step 1. In case there is no JSON file, just start from step 2. If there is a Network error display the appropriate information.
This SO question answers how to handle Network connections in iOS: How to check for an active Internet connection on iOS or OSX?
Saving file locally:
Assuming you have the unparsed JSON data in a NSString (responseString) do the following:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [NSString stringWithFormat:#"%#/%#", documentsDirectory, #"latest_json.json"];
NSError *error;
[jsonString_ writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:&error];
NSLog(#"%#", error)
Reading file
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [NSString stringWithFormat:#"%#/%#", documentsDirectory, #"latest_json.json"];
NSString *jsonString_ = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:&error];
Previous Answer
Embedding JSON file is similar to embedding any resource into your project. The following method shows you how I added an XML file and accessed it in my app.
Drag and drop your JSON/XML file to your resources group/folder in your XCode window. If you don't have the Resouces folder, it is better you create it. Then in your code do this:
NSString* filePath_ = [[NSBundle mainBundle] pathForResource:#"fileName" ofType:#"json"];
NSString *jsonString = [[NSString alloc] initWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error: NULL];
the variable jsonstring contails the JSON information. It is upto you how you would like to parse it.

Content is not retrieved from file

I've got this wired problem, I cannot get the content from the file and initiate my NSMutableArray with it.
Here's my code:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSLog(#"Does file exist?: %i", [[NSFileManager defaultManager] fileExistsAtPath:[NSString stringWithFormat: #"%#/length.txt", documentsDirectory]]);
NSMutableArray *tempArr;
tempArr = [[NSMutableArray alloc] initWithContentsOfFile:[NSString stringWithFormat: #"%#/length.txt", documentsDirectory]];
When trying this, initWithContentsOfFile returns (null). The row checking if the file exist prints '1' to the console.
This is the code I'm using to save the data:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
[length.text writeToFile:[NSString stringWithFormat: #"%#/length.txt", documentsDirectory] atomically:NO];
I'm using more or less exactly the same code in a different program without problems.
Really need some help here, perhaps I'm just blind for the moment...
When you try to create an array from the contents of a file, the file must be in plist format, and the outer-most plist element must be <array>. If it doesn't have that format, initialization will fail and your array will be nil.
You're creating the file by writing an NSString to a file, which means you should probably be reading it in to an NSString, not an NSArray.
The docs for NSArray's initWithContentsOfFile: method say:
Return Value An array initialized to contain the contents of the file
specified by aPath or nil if the file
can’t be opened or the contents of the
file can’t be parsed into an array.
The returned object might be different
than the original receiver.
You don't include the declaration of length in your code snippet, but I'm guessing that length.text returns an NSString object, not an NSArray. So you'd need to read that back from a file using initWithContentsOfFile: from NSString, not NSArray.

Resources