I need to save an image picked by an image picker on disk and than associate it to a managed object.
I want to store the image path in the managed object (imagePath attribute is nsstring) but I don't know how to call the image because it must be always available until user delete the managed object.
I thought to call every image with managed object's ID but I believe that it is too long and it's still temporary when I try to save my image...
How can I call every image for each managed object?
Thank you!
If you are going to store it on disk why not just store it in core data using the Transformable type.
You can shorten the managed object id using something like:
NSString *_id=[[self.objectID URIRepresentation] lastPathComponent];
Using the managed object's ID turned into a file name string is actually ideal since it is guaranteed to be unique. The length of the name is hardly an issue to the file system.
Related
I want to save a custom object array as NSData to NSUserDefaults that will be available at first run, is it possible? if so, how?
You should use the -registerDefaults: method to set any default values that you would like to have available before the user has set anything.
I have a Class for handling my data in my project, and now I need to store the data.
I'd like to use a Plist but I'm a bit unsure of how to start.
My class is pretty simple - 6 pieces of data, flat (no hierarchy).
I want my app to start with no data, so can I assume that I should create the PList programmatically once the User creates their first piece of data? (That is, don't create a .plist file in 'Supporting Files' prior to distribution?)
Then, when the app starts the next time, read the data and create an NSMUtableArray array of Class instances?
To create a property list, all you need to do is use appropriate types (i.e. those that support the property list format: NSData, NSString, NSDictionary, NSNumber, NSDate, NSArray), store them in a single container, and tell the containing object to write itself to a file. To read the data, you can initialize that same type using a path. For example:
// writing some data to a property list
NSString *somePath = ... // replace ... with the path where you want to store the plist file
NSMutableDictionary myDict = [NSMutableDictionary dictionary];
[myDict setObject:#"Caleb" forKey:#"name"];
[myDict setObject:[NSNumber numberWithInt:240] forKey:#"cholesterolOrIQ"];
[myDict writeToFile:somePath atomically:YES];
// reading the file again
NSDictionary *readDict = [NSDictionary dictionaryWithContentsOfFile:somePath];
The simplest way is to simple save an NSArray or NSDictionary to disk. Caleb's answer goes into detail there so I won't repeat it, other than to say you might have to convert a non-compatible object like NSColor to an property list object like NSData. It's up to you to do this each time you save or load your data.
NSKeyedArchiver and NSKeyedUnarchiver give you a little more control over the process, but work pretty much the same way. You provide (or get back) a plist compatible root object (usually an NSDictionary) that contains your data. I recommend creating a dictionary that includes your data structure as well as an arbitrary number (your app's build number is a good choice) to use as a version indicator. This way if you ever update your data model you can easily determine if you need to do anything to convert it to the new version.
If you're putting your own objects into the data file, look into NSCoding. The protocol gives you two methods using NSKeyedArchiver and NSKeyedUnarchiver to save and restore your data. This is by far the most straightforward approach if your data model consists of anything more than a few simple strings and numbers, since you're dealing with your own native objects. In your case, you would have your data class implement NSCoding and use the NSKeyedArchiver and NSKeyedUnarchiver methods to encode your six instance variables. When it's time to save or load, pack the instance of your class into an NSDictionary (along with a versioning number as I mentioned above) and call NSKeyedArchiver's archiveRootObject:toFile:. Your save an load methods deal only with your own data object, which makes things easy for you. The common pitfall to watch out for here is if your custom data object contains other custom object. This is fine, but you have to make sure every object that's going to be saved has its own NSCoding implementation.
Two things you can do:
Use NSUserDefaults:
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSUserDefaults_Class/Reference/Reference.html
The objectForKey method is the one you want to use to store your class. But, as pointed out in the comments, this shouldn't really be used for storing lots of user data; it's best for saving preferences.
For storing more data, you might want to look at Core Data. It's more complex, but should be better suited to your needs. Here's a tutorial on it:
http://mobile.tutsplus.com/tutorials/iphone/iphone-core-data/
Neither of these seems best for your simple application, but I leave this answer up since it gives alternatives for saving data to the iPhone.
I need to iterate through all the keys in my NSUserDefaults and transfer them to another format. Later I'll want to transfer them back, programatically.
I have a lot of keys and I have no way in my naming convention or by other means to determine if I used setObject or setInteger etc.
If I use setObject will this enable me to use integerForKey on that key ?
If I can't want can I use instead?
No, you should not be able to get the correct objects if you use integerForKey:. However you could get the correct objects if you use objectForKey:. This is because if you had used setInteger:forKey:, it automatically calls setObject:forKey:. So, there will be an object for the key. So what you have to do is iterate through the keys, get the objects using objectForKey: and convert it to the data type that you want.
I'm pretty sure using setObject will allow you to use integerForKey later.
Another way to go could be by adding a plist to your project and store everything in there. It's basically the same as NSUserDefaults is doing, only you'll be doing it all by hand. You can just read the contents of a plist to either an NSArray or an NSDictionary (whichever you chose to construct it with in the first place) and then access the members you need from that object.
Hope this helps.
Apple states that if you want to report a GKAchievement but you get a network error, the best way to handle this is to save the GKAchievement (possibly adding it to an array), then periodically attempt to report the achievement.
What is the best place to save the achievements? Would NSUserDefaults suffice, or would a property list be a better way?
When and how often should I attempt to report? On application launch, or something like every 10 minutes?
A property list can only handle specific classes (see "What is a Property List?"), which GKAchievement is not one of. NSUserDefaults uses property lists, so that's also out. GKAchievement does, however, conform to the NSCoding protocol, which means you can easily save them to disk using an NSKeyedArchiver. I would create an array of unreported achievements and read/write them like so:
//Assuming these exist
NSArray * unreportedAchievements;
NSString * savePath;
// Write to disk
[NSKeyedArchiver archiveRootObject:unreportedAchievements toFile:savePath];
// Read from disk
unreportedAchievements = [NSKeyedUnarchiver unarchiveObjectWithFile:savePath];
You can pretty much save anything in a property list (and thus NSUserDefaults) by turning it into NSData: archivedDataWithRootObject:
How to get the filename from a given UIImage object?
No you can't, since you can construct a UIImage from pure data without a file.
UIImage does not store the file name it was loaded from. You need to save it separately somewhere on download for future usage.