What is a good way to store a persistent array? - ios

I have an NSMutableArray of objects that I would like to persist between user sessions. Each object has an NSInteger property, and I would like to be able to access all of the objects for calculations using that property (averages, mins, maxes, etc.)
Would it be better to store that array into a Core Data database or just store my objects individually into the database?
EDIT: The array should hold no more than 1,000 items.

Depends on the size. If it's simple just archive the array to a file
Edited to add
If all you want to persist is an array you don't need to use the archiver methods, you can do it directly.
Imagine you have a file URL in your app's Documents directory called persistentURL which you want to use to save and read your array from.
All you need to do to persist the array is:
[yourArray writeToURL:persistentURL atomically:YES];
And when you want to read the data back into an array it's as simple as:
yourArray = [NSArray arrayWithContentsOfURL:persistentURL];
You can use this method here because the array contains only NSNumbers which are property list objects (i.e. objects that can be put directly into a plist).

NSArray and NSMutableArray can't contain integers directly. It has to contain NSNumber objects.
Anyway, I'd just use NSCoding. Try the methods archiveRootObject:toFile: (which writes directly to a file) or archivedDataWithRootObject (which converts the content to a byte-stream in NSData).
For <=1000 items it should be fast enough.
If you're reading and writing the array enough, you might want to consider using a malloc'ed C array of "long"s, and saving that as bytes to a file. That would be faster, and you could read/write values to your C array easily, instead of having to do object replacement. On the other hand resizing the array or inserting values is a pain with a C array, and you also have to be aware of data size and byte ordering issues if you will ever transfer this data between devices.
Edit: I just wrote a little test, and writing an NSArray of 1,000 NSNumbers to a file with archiveRootObject:toFile: takes about 0.0038 seconds on on old iPhone 4 I have around for testing. That's the slowest machine that supports iOS 7, and it's 3.8 THOUSANDTHS of a second, to write 1,000 items. So writing an array of 10,000 items should take 3.8 hundredths of a second or less.
Unless you are reading and writing this array many times a second in a loop, using archiveRootObject:toFile: is plenty fast enough.

Personally, I would use the following to store that array:
[[NSUserDefaults standardUserDefaults] setObject:myArray ForKey:#"myArray"]
and retrieve it anywhere in the app:
NSMutableArray *myArray = [[[NSUserDefaults standardUserDefaults] objectForKey:#"myArray"] mutableCopy];
That seems to me to be the easiest way to persist that data. You can store the mutable array in NSUser defaults, and I believe you'll need to create a mutable copy of it when you retrieve it later on to be able to continue to make changes to it.

Related

iOS - Reorder Items in CoreData

I have a tableView and an array locationsArray. The locations array is filled on viewDidLoad from data in my CoreData.
I have implemented the reorder methods on the tableView and that works fine however I can't figure out how to save the reordered array back into CoreData. I've tried deleting everything in CoreData and just saving the new reorderedArray. Although this is obviously very costly resource wise it seems to just load the elements back into the array in a seemingly random order.
Is there an easy way to do this that I am missing or can you not store things in CoreData in a certain order?
Strictly saying, it is impossible to store objects in certain order. You can only set the order for retrieved objects
When you retrieve locationsArray from CoreData, you have no any guaranties about their order.
The only way - add field to your Managed Object that will be used to order your locations.
Than, on retrieval, you'll be able to use locationsArray = [locationsArray sortedArrayUsing<#WhateverYouNeed#>];.
You can, also, achieve this by using sortDescriptors property of NSFetchRequest. It will provide you with desired behaviour from the box. The only downside of it, that your NSSortDescriptor in that case cannot be defined by block, so if you ordering is using some complex approach, you'll need to sort the result with already fetched data
use the predicate to sort the array or after fetching the array from coredata sort it using
NSArray *sortedlocationarray = [filteredlocationarray sortedArrayUsingDescriptors:#[sortDescriptor]];
where filteredlocationarray is from coredata.

Persisting NSCountedSet to NSUserDefaults

I need to persist an NSCountedSet of custom objects to NSUserDefaults.
I think the problem is that -(id)objectForKey: for NSUserDefaults has a special consideration in the docs here:
Special Considerations
The returned object is immutable, even if the value you originally set was mutable.
Question
How would I go about persisting an NSCountedSet if (as I am currently assuming?) NSUserDefaults returns a non-mutable NSSet from -(id)objectForKey: when I need to retain the internal count metadata that NSCountedSet contains?
You can't write an NSCountedSet to user defaults. Only arrays, dictionaries, strings, numbers, date and data.
You could create a dictionary matching the NSCountedSet, with the set elements as keys and the counts converted to NSNumber as values. And of course when you read the dictionary, convert it to a counted set. Just a few lines of code.
Alternatively, convert to an array with values duplicated depending on their count. If the counted set contains "Hello" with a count of 3, add it to the array three times.

What is the most reliable and fastest type or data structure to store data using Objective C?

I am looking for the type or data structure to store a big number of same type primitives on my app (Mac OS X or iOS) using Objective C. As I understood NSNumber stores only one primitive (correct me if I am wrong). I have, let's say, thousands of integers or strings. Which would be the best solution to put, store and access them there? NSSet, NSArray, NSMutableArray, NSDictionary, NSMutableDictionary or something else? I know that they have different features, but I care basically only about the performance of basic operations (putting, storing, retrieving).
It only depends on how you want to ADD, STORE and REMOVE this data.
First Let us go through each type of Data Structure that is available to us in Objective-C:
Primitive Array
This is the most basic type of storage in Objective-C(or C) which is used to store primitives.
Ex: int a[4] = {1, 2, 3, 4};
The limitation to this is
Can only store primitive types.
Array size cannot be changed once declared.
Can only be retrieved by its index.
Can store only single type of data, defined at the time of declaring the array.
NSArray
This is a container for storing objects. Any object which is of type NSObject (or inherits from NSObject) or is of type 'id' can be stored in NSArray.
Once initialized, it cannot be mutated i.e. array size cannot be changed nor the objects it contains can be modified. This is good in terms of security.
Objects can only be accessed by its index.
NSMutableArray
Same as NSArray, but
Can be mutated, i.e. the existing objects can be modified and also new objects can be added or deleted.
NSSet
Same as NSArray but
Stores only unique objects.
Objects cannot be accessed by its index. Objects can only be accessed by enumeration.
NSMutableSet
Same as NSSet, but
Can be mutated, i.e. objects can be added or removed at a later point of time.
NSOrderedSet
Same as NSArray, i.e. objects are stored and retrieved by an index, but
Stores only unique objects.
NSMutableOrderedSet
Same as NSMutableArray, but
Stores only unique objects.
NSDictionary
Can store any type of data.
Objects are stored and retrieved by a key.
Once initialized, cannot be mutated i.e. cannot add new key-values nor can update existing objects associated to a particular key.
NSMutableDictionary
Same as NSDictionary
Can be mutated, i.e. new objects can be added or removed and existing objects can be modified.
This was a short description about mostly used Data Structures in Objective-C. These are used based on the need of the program and how data is to be manipulated.
Therefore,
If you want to store thousands of numbers and strings and want access it by its index value then use NSMutableArray. If you are not going to add, remove or modify any objects in the future then use NSArray.
If you want to store data but do not want duplicates and want to access it by its index the use NSOrderedSet/NSMutableOrderedSet
If you want to store data but do not want duplicates and its order also doesn't matter then use NSSet/NSMutableSet.
If you want to access data by a particular key then use NSDictionary/NSMutableDictionary
Regarding Performance
Since NSSet doesn't contain any order, they are more performant than NSArray
Here is a very good and detailed article on performance characteristics for each Data Structure discussed above
Class Time [ms] 1,000,000 elements
Adding
NSMutableOrderedSet 3190.52
NSMutableDictionary 2522.47
NSMutableSet 2511.96
NSMutableArray 1423.26
NSSet 8.03
Random Access
NSMutableOrderedSet 10.74
NSMutableDictionary 9.18
NSMutableArray 8.08
NSMutableSet 4.47
NSSet 3.56
To know more about Objective-C Data Types and Data Structure, read this

core data, storing images in a dictionary

I have an app that feature "pages". Each page can have n number of images, depending on user preference. To store the images and associate the image with the correct view etc, I am building a dictionary for each image, then storing that dictionary in an array of image dictionaries, which I save to core data as binary data. I am storing the image itself as an object in the dictionary, like below. Is this an efficient and safe way to do this? Seems to work ok...
imageDictionay = [NSMutableDictionary dictionaryWithObjectsAndKeys:image, #"image", imageTag, #"tag", imageTransformString, #"transform", nil];
That way will certainly work, but I would personally create another entity for ImageInfo like so:
If you are going to have a dictionary with the same three keys, it makes more sense to me to have an entity with those three attributes.
Also, if you are really worried about performance, you could also write the image to disk and just put a string in Core Data to tell you where the image is stored.

Nsdictionary as a data type

Would nsdictionary be a good data type to use for storing long string values as values and names of those descriptions for keys? Or would a different data type be more effective? I am using it for animals, and having and array hold all the data then using a dictionary to point to the name and description of the animal. I'm just curious if this is used for smaller data like states and capitals
Or should I just use a #Define #"rhino description"
[Animal animalObj:#"rhino" location:#"the water" description:[[self setGenericAnimals] valueForKey:#"Rhino"]]
NSDictionary is OK for this. Whats great about using NSDictionary is you can save your data as JSON in a sperate file and then serialzie it into a NSDictonary when you need it. This would make it easier for you to manage all your data and it seperates it from your application.
this is a good start on how to convert JSON into a NSdictionary.
http://www.raywenderlich.com/5492/working-with-json-in-ios-5
Remember though that the entire NSDictionary must fit into memory so if your going to have thousands of strings you might want to separate that into different JSON files and then serialize them into Dictionaries when you need them.
Another thing to remember is that if you want to do simple comparisons and sorting options on objects you are better using CoreData as this allows you to store lots of strings and easily access them.

Resources