In my iPhone app, I have a class called Contact
which consists of an ABRecordRef
to serve as a reference to a particular contact.
I need to store groups of these contacts in NSUserDefaults
, but things aren't working out so well since Contact
is a custom class.
Any ideas of what to do in this case?
It appears the limit is the maximum file size for iOS (logically), which is currently 4GB: https://discussions.apple.com/thread/1763096?tstart=0. The precise size of the data is circumscribed by the compiler types (NSData, NSString, etc.) or the files in your asset bundle.
The user's defaults database is stored on disk as a property list or plist. A property list or plist is an XML file. At runtime, the UserDefaults class keeps the contents of the property list in memory to improve performance. Changes are made synchronously within the process of your application.
Storing Default Objects The NSUserDefaults class provides convenience methods for accessing common types such as floats, doubles, integers, Boolean values, and URLs.
Saving to NSUserDefaults : Basically, all you have to do is load NSUserDefaults, and then tell it to save a value to a specific key. Here is a simple example of writing an integer to NSUserDefaults: NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
You cannot use NSUserDefaults
for a custom class. From the documentation:
The
NSUserDefaults
class provides convenience methods for accessing common types such as floats, doubles, integers, Booleans, and URLs. A default object must be a property list, that is, an instance of (or for collections a combination of instances of):NSData
,NSString
,NSNumber
,NSDate
,NSArray
, orNSDictionary
. If you want to store any other type of object, you should typically archive it to create an instance ofNSData
.
Try using NSData
. For example, to load custom objects into an array, you can do
NSUserDefaults *currentDefaults = [NSUserDefaults standardUserDefaults];
NSData *dataRepresentingSavedArray = [currentDefaults objectForKey:@"savedArray"];
if (dataRepresentingSavedArray != nil)
{
NSArray *oldSavedArray = [NSKeyedUnarchiver unarchiveObjectWithData:dataRepresentingSavedArray];
if (oldSavedArray != nil)
objectArray = [[NSMutableArray alloc] initWithArray:oldSavedArray];
else
objectArray = [[NSMutableArray alloc] init];
}
To archive the data, use:
[[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:objectArray] forKey:@"savedArray"];
This will all work so long as your custom object complies with the NSCoding
protocol:
- (void)encodeWithCoder:(NSCoder *)coder;
{
[coder encodeObject:label forKey:@"label"];
[coder encodeInteger:numberID forKey:@"numberID"];
}
- (id)initWithCoder:(NSCoder *)coder;
{
self = [[CustomObject alloc] init];
if (self != nil)
{
label = [coder decodeObjectForKey:@"label"];
numberID = [coder decodeIntegerForKey:@"numberID"];
}
return self;
}
ABRecord
is an opaque C type, so it's not an object in the sense of Objective-C. That means you can not extend it, you can not add a category on it, you can not message it. The only thing you can do is call functions described in ABRecord
Reference with the ABRecord
as a parameter.
You could do two things to be able to keep the information referenced by the ABRecord
around:
Get the ABRecord
s id
by ABRecordGetRecordID()
. The ABRecordID
is defined as int32_t so you can cast it to an NSInteger
and store it wherever you like. You can later get the record back from ABAddressBookGetPersonWithRecordID()
or ABAddressBookGetGroupWithRecordID()
. However, the record could be changed or even deleted by the user or another app meanwhile.
Copy all values inside the record to a standard NSObject
subclass and use NSCoding
as discussed above to store it. You will then, of course, not benefit from changes or additions to the record the user could have made.
Well, Apple's recommendation is to store the record identifier, the first name, and the last name. You can then try retrieving the contact from the address book by the identifier and, if the record isn't found or if it's not the right person, try retrieving by first and last name (since record identifiers may change depending on the source of your address book data).
This may or may not be what you want, depending on why you're storing the data. But, you could pretty easily put those three values into an NSDictionary and write the dictionary to NSUserDefaults
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With