local memory as well as webservice - ios

even after so many research i haven't found a solution for this question. I am currently working on a app which uses 3 view controllers for Registration with a log out button. the last view controller has the Register button which saves all the details of registration in a web service. But if the user has filled the two view forms and logs out. The two view filled forms field should be saved in the local memory and wen the user logs it again the pre filled forms should load the fields saved in internal memory just to continue the Registration for webservice. Any idea how to implement this sort of functionality

As others have said, NSUserDefaults will suffice for what you need.
NSUserDefaults *registrationInfo = [NSUserDefaults standardUserDefaults];
Guessing you have text fields with the info you need. So pull out the text and save to a key like this.
[registrationInfo setObject:self.someTextFieldName.text forKey#"firstTextField"];
After repeating this for every text field(use different key names though), call this [registrationInfo synchronize];
To pull the data out, you open the defaults again just like the first line. And to retrieve a specific key: NSString *firstTextField = [registrationInfo objectForKey:#"firstTextField"];
To make this easier, you can also put all of your strings in an array or dictionary, and then add that as an object in your defaults. Then you only have to set/get once.

If you have large amount of data to save use CoreData else you NSUserDefaults to save it.

I suggest you to use PLIST There are mainly three steps to do this.
1) Generate .plist file.
NSError *error1;
BOOL resourcesAlreadyInDocumentsDirectory;
BOOL copied1;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath1 = [documentsDirectory stringByAppendingString:#"/epub.plist"];
resourcesAlreadyInDocumentsDirectory = [fileManager fileExistsAtPath:filePath1];
if(resourcesAlreadyInDocumentsDirectory == YES) {
} else {
NSString *path1 = [[[NSBundle mainBundle] resourcePath] stringByAppendingFormat:#"/epub.plist"];
copied1 = [fileManager copyItemAtPath:path1 toPath:filePath1 error:&error1];
if (!copied1) {
NSAssert1(0, #"Failed to copy epub.plist. Error %#", [error1 localizedDescription]);
}
}
2) Try to read(open) it.
NSMutableDictionary* dict = [[NSMutableDictionary alloc] initWithContentsOfFile:filePath1];
3) write data to plist file.
[dict setObject:[NSNumber numberWithInt:value] forKey:#"value"];
[dict writeToFile:path atomically:YES];
This is a simple way to use it. I suggest to use .plist file in place of NSUserDefaults.

Related

Will property list data persist after killing the application?

I have created a custom property list file. The file is stored in the application document.
While user login is successful the login information is stored in the plist, and it is working fine.
The plist content are cleared while log out, this also works fine.
When i am still login i killed the application. When the app opens the plist data i cleared.
code used to save to file:
NSArray *paths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = [paths objectAtIndex:0];
NSString *plistPath = [documentsPath stringByAppendingPathComponent:#"xxxxPlist.plist"];
if (![[NSFileManager defaultManager] fileExistsAtPath:plistPath])
{
plistPath = [[NSBundle mainBundle] pathForResource:#"xxxxPlist" ofType:#"plist"];
}
dict=[[self cleanDictionary:[dict mutableCopy]] mutableCopy];
NSDictionary *plistDict=[[NSDictionary alloc] initWithObjectsAndKeys:dict,#"login_data", nil];
NSError *error = nil;
NSData *plistData = [NSPropertyListSerialization dataWithPropertyList:plistDict format:NSPropertyListXMLFormat_v1_0 options:NSPropertyListImmutable error:&error];
if(plistData)
{
[plistData writeToFile:plistPath atomically:YES];
}
else
{
//error here
NSLog(#"%# ",error);
}
code used to fetch data
NSArray *paths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = [paths objectAtIndex:0];
NSString *plistPath = [documentsPath stringByAppendingPathComponent:#"xxxx.plist"];
if (![[NSFileManager defaultManager] fileExistsAtPath:plistPath])
{
plistPath = [[NSBundle mainBundle] pathForResource:#"xxxxPlist" ofType:#"plist"];
}
NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:plistPath];
return [dict objectForKey:#"login_data"];
I there any way out to persist the data?
There are several things that may be causing problems
When saving to file
1) My understanding is that you specifically want to save to /Documents folder specifically to ensure your file persists
2) So you correctly build following path
"/Documents/xxxxPlist.plist"
3) But then why do you check if a file already exists at that location?
if (![[NSFileManager defaultManager] fileExistsAtPath:plistPath])
{
plistPath = [[NSBundle mainBundle] pathForResource:#"xxxxPlist" ofType:#"plist"];
}
You just have to write to the path when you are ready.
If there is an old file at this location it will be overwritten.
And my understanding is this is the wanted behaviour, because you've already read that file and the data is in that dictionary "dict".
4) Also, by asking NSBundle to give you path for your file name
"xxxxPlist.plist"
there is a risk that it will just give you back some other path with file named the same (not in /Documents) if such file happens to exist. For example if you happened to write to say, /Cache folder earlier (with different code), your app will keep getting the /Cache path and keep reading/writong there (not in /Documents). And with the existing code you would have gotten nil here for path on the very first run, so not sure how he file got created in the first place.
5) Then I am not sure what exactly does this line
dict=[[self cleanDictionary:[dict mutableCopy]] mutableCopy];
Why first make a mutable copy, then presumably get immutable copy back and get a mutable one of it. Can't -cleanDictionary: just return the same mutable copy it was passed?
When reading from file
1) Not sure why you're searching for a different file first?
"/Documents/xxxx.plist" not "/Documents/xxxxPlist.plist"
Also what happens if "xxxx.plist" exists, then you'll never get to "xxxxPlist.plist" that you are writing in the other section.
2) Then, yes, you have to check if a file exists at certain path before you try to read it. But, in your case, if it does not exist, you don't ask NSBundle for another location, because you need your specific file in /Documents, and you don't know what you'll get from NSBundle, if your file is not where it should be.
So if there is no "xxxxPlist.plist" file, it's just your first run of the app and you will be creating your initial dict.

Loading files from disk to NSMutableArray removes NSMutableArray from memory

I'm loading a file to a NSMutableArray. I'm doing it like this:
if(!self.dataArray){
self.dataArray = [[NSMutableArray alloc] init];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
NSString *arrayPath = [[paths objectAtIndex:0]
stringByAppendingPathComponent:#"array.out"];
self.dataArray = [NSMutableArray arrayWithContentsOfFile:arrayPath];
}
The array that is loaded into the file consists of multiple NSDictionaries.
However, this somehow deallocates the array in the memory because when I log dataArray after doing this, it logs nil. How come?
Update
I've figured out that [NSMutableArray arrayWithContentsOfFile:arrayPath] is logging nil because the code in which I'm uploading the content to the file, doesn't create the file:
// write data to disk
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *arrayPath = [[paths objectAtIndex:0]stringByAppendingPathComponent:#"array.out"];
[self.dataArray writeToFile:arrayPath atomically:YES];
NSLog(#"uploaded file: %#", arrayPath); // logs an arrayPath, but one that doesn't exists.
Check the following,
Check the dataArray is a weak property ? If so, change to strong.
Check the file exists at path, using
[[NSFileManager defaultManager] fileExistsAtPath:arrayPath];
Verify the file have expected content, by logging it.
Confirm the File content is organized as a property list (plist). Verify it in plist editor/Xcode.
If you dynamically creating it, check the path you are writing to.
Confirm the method of writing NSArray to plist. Use
[array writeToFile:path atomically:YES];
Note:
If you are dynamically creating the file and you are testing on Simulator; you can
find the file by logging file path and following it on Finder.
Property List Reference
Apple documentation
Per Apple documentation, the array returns nil if the file can’t be opened or if the contents of the file can’t be parsed into an array.
Did you use the [writeToFile:atomically:] method to write the array to a file?
Also, make sure that the filePath string matches exactly on both write and read ends. I've wasted a lot of time trying to hunt down a bug when it turned out I had misspelled the name of the file or used the wrong file extension.
Another possibility: have you confirmed that this code is being executed? Sometimes I've had to change (!self.someProperty) to (self.someProperty != nil) in my if condition to get code like this to run.
Peter Segerblom and wildBillMunson are right: the array returns nil if the file can't be opened or if its content can't be parsed into an array.
You said "array.out" is an array of NSDictionaries. Whenever I have that set of data, I use the plist type of file and read it this way:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
NSString *directory = [paths objectAtIndex:0];
NSString *fullPath = [directory stringByAppendingPathComponent:#"data.plist"];
NSString *errorDesc = nil;
NSPropertyListFormat format;
NSData *plistXML = [[NSFileManager defaultManager] contentsAtPath:fullPath];
NSArray *data = (NSArray *)[NSPropertyListSerialization propertyListFromData:plistXML mutabilityOption:NSPropertyListMutableContainersAndLeaves format:&format errorDescription:&errorDesc];
Be sure to check if fullPath is not returning nil.
Hope this helps!

Optimum way to make an auto back up of photos on server?

What I've known:
How make requests to server for uploading I will use AFNetworking
How access photos and videos with help of ALAssetsLibrary
I think I must use CoreData to keep info about:last syncing, photos already uploaded, etc. I worked already with coreData it will no be a problem.
My problems are logic, flow how can achieve this auto back up and of course to be optimum(minimum requests, short way). What steps must follow to achieve this scope?
Any thoughts?
I think CoreData is too heavy in this situation. You may want to use plist to store your info data .here are some steps to follow .
After loading image from server, create a dictionary to store the message you want and create another dictionary to store these messages , and use image's url as the key of this dictionary. It might look like this:
imageUrl = {
lastSyncTime = xxxxxxxxxx,
photoUploaded = 0,
}
Create a plist file to save this dictionary:
- (NSString *)filePath:(NSString *) fileName{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
return [documentsDirectory stringByAppendingPathComponent:fileName];
}
[yourImageDictionary writeToFile:[self filePath:#"imageInfo.plist"] atomically:YES];
Read or write your plist file anytime you want:
if ([[NSFileManager defaultManager] fileExistsAtPath:[self filePath:#"imageInfo.plist"]]) {
NSDictionary *imageInfo = [NSDictionary dictionaryWithContentsOfFile:[self filePath:#"imageInfo.plist"]];
}

I have uploaded application with core data and I want to replace new core data without migration. Does apple allows it?

I want to replace core data and want to delete old core data. Does Apple allows it to delete old core data. Is there any chance to reject app.
Apple won't care, but your users might. If there is data that your users might be sorry to lose, you should make every effort to migrate it or give an option to export it when they upgrade.
If you're only using core data to cache downloaded values, then there's no problem with this at all. In fact, deleting the old store would be necessary to prevent the app crashing on upgrade, since it wouldn't be able to migrate from the existing store. The best place to do this is in the core data setup code when you receive an error - the boilerplate comments guide you toward this.
There are no problems doing that.
For example, you can check app's version in the AppDelegate:
- (void)clearCacheIfNeeded;
{
NSString *savedVersion = [[NSUserDefaults standardUserDefaults] objectForKey:#"currentVersion"];
NSString *currentVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleVersion"];
if (![savedVersion isEqualToString:currentVersion]) {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cachesDirectory = [paths objectAtIndex:0];
NSArray *contents = [fileManager contentsOfDirectoryAtPath:cachesDirectory error:NULL];
NSEnumerator *e = [contents objectEnumerator];
NSString *filename;
while ((filename = [e nextObject])) {
NSLog(#"file name: %#", filename);
[fileManager removeItemAtPath:[cachesDirectory stringByAppendingPathComponent:filename] error:NULL];
}
[[NSUserDefaults standardUserDefaults] setObject:currentVersion forKey:#"currentVersion"];
}
}

How do I save user preferences for my iPhone app?

The question title pretty much gives it away - I'd like my app to remember a few things. It's some sort of calculator, so it should save the last used values and some user selectable settings.
Basically I'd like to save a handful of floats and BOOLs and load them again the next time the app loads.
What's the best and easiest way to do that?
Thanks!!
One of the easiest ways would be saving it in the NSUserDefaults:
Setting:
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject:value
forKey:key];
// – setBool:forKey:
// – setFloat:forKey:
// in your case
[userDefaults synchronize];
Getting:
[[NSUserDefaults standardUserDefaults] objectForKey:key];
– boolForKey:
and
– floatForKey: in your case.
Besides the very good NSUserDefaults approach, there is another easy way to store data from an NSArray,NSDictionary or NSData in a file. You can use these methods as well:
- (BOOL)writeToFile:(NSString *)path atomically:(BOOL)flag
respectively (for a NSDictionary):
+ (id)dictionaryWithContentsOfFile:(NSString *)path
you just have to give a valid path to a location. According to the iOS Application Programming Guide, the /Library/Caches directory would be the best place to store data that you need to persist between app launches. (see here)
In order to store/load a dictionary from a filed called "managers" in your document directoy you could use these methods:
-(void) loadDictionary {
//get the documents directory:
NSArray *paths = NSSearchPathForDirectoriesInDomains (NSCachesDirectory, NSUserDomainMask, YES);
NSString *cacheDirectory = [paths objectAtIndex:0];
//create a destination file name to write the data :
NSString *fullFileName = [NSString stringWithFormat:#"%#/managers", cacheDirectory];
NSDictionary* panelLibraryContent = [NSDictionary dictionaryWithContentsOfFile:fullFileName];
if (panelLibraryContent != nil) {
// load was successful do something with the data...
} else {
// error while loading the file
}
}
-(void) storeDictionary:(NSDictionary*) dictionaryToStore {
//get the documents directory:
NSArray *paths = NSSearchPathForDirectoriesInDomains
(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cacheDirectory = [paths objectAtIndex:0];
//make a file name to write the data to using the
//cache directory:
NSString *fullFileName = [NSString stringWithFormat:#"%#/managers", cacheDirectory];
if (dictionaryToStore != nil) {
[dictionaryToStore writeToFile:fullFileName atomically:YES];
}
}
Anyway this approach is very limited and you have to spend a lot of extra work if you want to store more complex data. In that case the CoreData API is very very handy.
In Swift:
Setting
let userDefaults = NSUserDefaults.standardUserDefaults()
userDefaults.setObject(value, forKey: key)
// userDefaults.setFloat(12.34, forKey: "myFloatKey")
// userDefaults.setBool(true, forKey: "myBoolKey")
Note that for iOS 8 and later, calling userDefaults.synchronize() is not recommended.
Getting
let userDefaults = NSUserDefaults.standardUserDefaults()
if let value = userDefaults.objectForKey(key) {
print(value)
}
Note that userDefaults.boolForKey and userDefaults.floatForKey both return non optional values, so they would never be nil (only false or 0.0).
Further reading
NSUserDefaults — A Swift Introduction
You are looking for NSUserDefaults
Swift 4 / Linux
Apparently something has changed. Now there's the UserDefault class.
Check these links:
https://developer.apple.com/documentation/foundation/userdefaults
https://www.hackingwithswift.com/read/12/2/reading-and-writing-basics-userdefaults

Resources