Encode NSArray or NSDictionary using NSCoder - iphone

I was wondering whether or not it is possible to use the NSCoder method:
- (void)encodeObject:(id)objv forKey:(NSString *)key
to encode either an instance of NSArray or NSDictionary. If not how do you go about encoding them? I am trying to use NSKeyedArchived / NSKeyedUnarchiver to send data between phones using GameKit. I tried it and cannot seem to retrieve the string I stored in my array. The packet class I made comes through along with the packet type integer, but not the data in the array it seems.
Thanks in advance!

If the array or dictionary is the root object you should do
NSData * encodedData = [NSKeyedArchiver archivedDataWithRootObject:someArray];
or
BOOL success = [NSKeyedArchiver archiveRootObject:someArray toFile:filePath];
If it is an instance variable of a custom class, in the -encodeWithCoder: method should do
[coder encodeObject:someArray forKey:#"someArray"];
and then in the -initWithCoder: method
someArray = [[coder decodeObjectForKey:#"someArray"] retain];

What kind of objects are you storing in the array? Make sure that all objects stored in the array implement the NSCoding protocol.

NSKeyedArchiver/Unarchiver should encode and decode NSArrays and NSDictionaries with no problem. If your packet class you've created implements the NSCoding protocol, you need to explicitly call [encodeObject:myNsArrayforKey:#"stringsArray"] in your -encodeWithCoder: method (assuming that myNsArray is the name of the instance variable in your packet object you want to encode). But then the archiver and NSArray should take care of the rest of it. If you're doing this, it would be helpful to hear more about the layout of your classes and who's calling who when encoding/decoding.

Related

How to use an object as a key in Objective-C

I would like to use a custom object as a key in a hash-like structure. I've tried using NS[Mutable]Dictionary but in order for my object to be a key it has to implement the NSCopying protocol. NSDictionary is sending a copy message to all of it's keys as far as I've read. I don't want to implement the protocol (my object is quite complex) nor do I want it to be copied. What are my options? Do I have any?
NSDictionary is toll-free bridged with CFDictionaryRef, but they actually differ in behavior when adding objects. Specifically, NSDictionary's -setObject:forKey: will copy the key, but CFDictionaryRef's CFDictionarySetValue() will not copy the key. This means that if you want to use non-copyable keys, you can use CFDictionarySetValue() instead to add it to the dictionary.
CFDictionarySetValue((CFMutableDictionaryRef)myDict, myKey, myValue);
This will still retain the key, but it won't copy it. And you can use the normal NSDictionary methods for everything else.
Do you need the NSDictionary to retain the object? If not, you can turn it into an NSValue and use that as the key:
NSValue *value = [NSValue valueWithNonretainedObject:yourCustomObject];
[dictionary setObject:someObject forKey:value];
This can get a bit messy but is in alternative to implementing NSCopying.
You can roll your own dictionary. Not really that hard.
Another option is to use a surrogate object, containing a pointer to "the" object. The surrogate would implement the hash and either copy or reference the fields to be compared for isEqual. It could do a basic sanity check to assure the compared fields have not been changed when it's referenced.
You could just do this:
- (id)copyWithZone:(NSZone *)zone {
return [self retain];
}

How to save my own object with NSKeyedArchiver?

i've got problems using the NSKeyedArchiver/NSKeyedUnarchiver for saving my object.
I added the methods - (id)initWithCoder:(NSCoder *)decoder and - (void)encodeWithCoder:(NSCoder *)encoder. The problem is when i try to save the object it doesn't work correctly.
I could imagine a problem (but I'm not sure if it is the problem ;) ). I have some arrays within my object. They contain more objects (I implemented both of the "Coder"-Methods as well). So does the array call the methods in it's objects?
Any possible solution??
Thanks!!
In the header file indicate that your class will implement the NSCoding protocol, like <NSCoding>
In the encodeWithCoder method you need to encode all the fields you want to save like so:
[encoder encodeObject:array1 forKey:#"array1"];
Then in the initWithCoder method, decode the fields that were encoded:
array1 = [coder decodeObjectForKey:#"array1"];
Be sure that any encoded containers only contain objects that also implement the NSCoding protocol. This could be core classes such as NSString, NSNumber, NSArray, NSDictionary, as well as your own custom object.
If your project is not using garbage collection you need to retain or copy the data retrieved from the archive like so:
array1 = [[coder decodeObjectForKey:#"array1"] retain];

Serialize an Array of data

I currently write to and read from an array of data, and use the index of each element to achieve something. I need a way to store this array, I looked at the user defaults, but that stores a dictionary, with retieval using keys. I will not know what key was stored.
What is the best was to store ths array of data on the iphone?
Regards
NSKeyedArchiver, a concrete subclass
of NSCoder, provides a way to encode
objects (and scalar values) into an
architecture-independent format that
can be stored in a file.
So you can serialize anything you like to a file:
// need a path
- (NSString*) getPath
{
NSString* path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
return [path stringByAppendingPathComponent:#"someInfo"];
}
// save an array
- (void) save:(NSArray*)array
{
[NSKeyedArchiver archiveRootObject:array toFile:[self getPath]];
}
// get that array back
- (NSArray*) load
{
return [NSKeyedUnarchiver unarchiveObjectWithFile:[self getPath]];
}
You might want to serialize a dictionary of arrays if you have more than one you want to store.
It is possible to store an array in NSUserDefaults. It does however depend on the kind of objects the array holds. NSKeyedArchiver is another good option, as is storing the array as a plist. It could even be that CoreData is the best choice for you. It all depends on the expected size of your data and how you use it. NSKeyedArchiver seems a fair enough middle ground for many situations, but to answer you question more info is needed.

Separate NSData into smaller NSMutableData objects

I am unsure of how to separate a NSData object into smaller parts so that I can send it over bluetooth. I believe it is a method similar to this:
- (void)getBytes:(void *)buffer range:(NSRange)range
I do not know what to pass in for the buffer. Do I just pass in a NSMutableData object to hold the bytes that I pull out of the original NSData?
Thanks
You can use the -subdataWithRange: method.

Need to convert NSData to NSArray

I am pulling down a plist from a URL using an NSURLConnection, which returns an
NSData object. I would like to convert this to an NSArray. Can anyone help me?
I am refactoring a method that currently does a synchronous request to the URL,
using arrayWithContentsOfURL: to get the NSArray.
Thanks!!
Use +[NSPropertyListSerialization dataWithPropertyList:format:options:error:] to convert the data, then check if the result -isKindOfClass:[NSArray class].
Use NSKeyedArchiver for archiving object to data.
NSKeyedUnarchiver for unarchiving object from data:
NSArray *object = [NSKeyedUnarchiver unarchiveObjectWithFile:self.receivedData];