Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

iOS

Nicholas Breeser
Nicholas Breeser
5,786 Points

Moving from NSUserDefaults to Core Data

I am in a bit of a pickle. I have an application that is live in the iOS app store called To Due. It is a task managing application that syncs via iCloud. All data is stored in NSUserDefaults and synced by MKiCloudSync from GitHub. Apple approved this app and it has been live for a month or so now.

I made a companion to my iOS app for Mac which was just rejected with the accompanying reason:

"The app is using iCloud APIs improperly. The app is using Key-Value Data to store user generated data content. The space available for Key-Value Data storage is limited and should be used for application related settings and/or preferences. It would be appropriate to use the NSDocument APIs to manage the user generated content on iCloud."

The mac app uses the exact same NSUserDefaults and MKiCloudSync methods to store and manage data. When asked why my iOS app was approved and my Mac app rejected, they responded that I should be using NSDocument storage.

Does this mean I need to transition from NSUserDefaults to Core Data? Is there any way to get an Array of Dictionaries (my current data structure) out of Core Data? (one dictionary per row in the table) Lastly, is there a way to just avoid Core Data and sync NSUserDefaults through an NSDocument (if that makes any sense)?

Any help would be immensely appreciated!!!

2 Answers

Patrick Cooney
Patrick Cooney
12,216 Points

You probably want to tag Amit Bijlani or Ben Jakuben on this one for a more timely response. I'm not sure many in the treehouse community are at the level where they can confidently recommend how you should proceed.

Amit Bijlani
STAFF
Amit Bijlani
Treehouse Guest Teacher

iCloud does not mean that you have to store data using Core Data. If you were using NSUserDefaults then you can easily store data in a plist. Maybe this might help: http://stackoverflow.com/questions/8409151/sharing-a-plist-file-using-icloud

Nicholas Breeser
Nicholas Breeser
5,786 Points

Thanks, Patrick, for tagging Amit!

Amit, thanks so much for your help!! I was dreading the idea of trying to move all data from NSUserDefaults to something else. I really appreciate your time!

Nicholas Breeser
Nicholas Breeser
5,786 Points

Actually, Amit Bijlani , would you be able to describe the best wait to easily access the NSUserDefaults plist? Do I have to create my own plist and copy the NSUserDefaults' contents in order to have a plist accessible for iCloud to sync, or can I directly get the NSUserDefaults plist from the bundle?

Thanks again for your help!

Amit Bijlani
Amit Bijlani
Treehouse Guest Teacher

You cannot or should not directly access the NSUserDefaults plist, you would need to create your own plist. It also depends on your needs, you could probably get away with using NSUbiquitousKeyValueStore which has a limit of 1mb. If so, then you can use SDCloudUserDefaults. If not then see this: iCloud KeyValue Storage

Nicholas Breeser
Nicholas Breeser
5,786 Points

Thanks for the reply Amit. That is actually what got me in trouble in the first place. Since the content in my NSUserDefaults file is actually small amounts of "user generated content" Apple will not let me use iCloud Key-Vlaue storage and is insisting I use NSDocument Storage. I dont want to have to rewrite how my app locally saves and works with data (setting and retrieving a array of dictionaries for a key in NSUserDefaults) so I want to take that info and put it in a plist that uses NSDocument to sync. This way I make Apple happy because I am not using KeyValue storage and am instead syncing a plist file. I think I just got what I want with this:

NSString *destPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; destPath = [destPath stringByAppendingPathComponent:@"Data.plist"];

            // If the file doesn't exist in the Documents Folder, copy it.
            NSFileManager *fileManager = [NSFileManager defaultManager];

            if (![fileManager fileExistsAtPath:destPath]) {
                NSString *sourcePath = [[NSBundle mainBundle] pathForResource:@"Data" ofType:@"plist"];
                [fileManager copyItemAtPath:sourcePath toPath:destPath error:nil];
            }

            [sortableArray writeToFile:destPath atomically:YES];
            contents = [[NSMutableArray alloc] initWithContentsOfFile:destPath];
            NSLog(@"the contents array is %@", contents);

Where sortableArray is the array that is being stored in NSUserDefaults and being used throughout the application to persist data and contents array is there as a verification that my sortableArray is saved in the plist that is newly placed in the documents directory. This Data.plist from the documents directory would then use NSDocument to sync.

Am I correct in saying this and would this solution work?

Sorry about having such a hassle-some question. I truly appreciate all your help!