iPhone App : EncodeObject in NSKeyedArchiver trouble - iphone

In an iPhone App, I have a NSDictionary object which has its key as NSString, and value is a custom object. Am trying to convert this to NSData for iCloud.
I did this:
NSMutableData *data = [NSMutableData data];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc]
initForWritingWithMutableData:data];
[archiver encodeObject:myDictionary forKey:#"mykey"];
[archiver finishEncoding];
Now, the encodeObject line is throwing this exception (NSDictionary object 'myDictionary' has values in it. I checked.) :
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[ConnectionProfile encodeWithCoder:]: unrecognized selector sent to instance 0x1f849350'
ConnectionProfile is the object I have stored as the value in NSDictionary. Should it implement NSCoding explicitly?

Got it. Yes. As I suspected, ConnectionProfile had to implement NSCoding. And now, the error's gone.

Related

NSURL getFileSystemRepresentation:maxLength

Im having error with this code
NSString *theURL = #"http://www.w3schools.com/xml/cd_catalog.xml";
NSData *theData=[NSData dataWithContentsOfFile:[NSURL URLWithString:theURL]];
NSDictionary *theDic=[XMLReader dictionaryForXMLData:theData error:nil];
error is
2013-02-10 00:39:05.113 MyXml[4139:c07] -[NSURL getFileSystemRepresentation:maxLength:]: unrecognized selector sent to instance 0x7139670
2013-02-10 00:39:05.115 MyXml[4139:c07] *** Terminating app due to uncaught exception
'NSInvalidArgumentException', reason: '-[NSURL getFileSystemRepresentation:maxLength:]: unrecognized selector sent to instance 0x7139670'
*** First throw call stack:
(0x1c96012 0x10d3e7e 0x1d214bd 0x1c85bbc 0x1c8594e 0xad3ee4 0xad3e92 0xad3de2 0xaf2336 0x2bb8 0x15157 0x15747 0x1694b 0x27cb5 0x28beb 0x1a698 0x1bf1df9 0x1bf1ad0 0x1c0bbf5 0x1c0b962 0x1c3cbb6 0x1c3bf44 0x1c3be1b 0x1617a 0x17ffc 0x295d 0x2885)
libc++abi.dylib: terminate called throwing an exception
it is giving error because you are initing NSData with file by help of dataWithContentsOfFile, but actually you are giving URL to the NSData for initing it. because of this your code indirectly calling method of file getFileSystemRepresentation:maxLength: on NSURL ,thats why it is giving error-Unknown selector.
use this dataWithContentsOfURL instead of dataWithContentsOfFile
NSString *theURL = #"http://www.w3schools.com/xml/cd_catalog.xml";
NSData *theData=[NSData dataWithContentsOfURL:[NSURL URLWithString:theURL]];

JSONKit invalid arguement when try to copy

I am parsing JSON data with JSONKit as NSMutableDictionary.
NSString *str = [[NSString alloc] initWithData:self.responseData encoding:NSUTF8StringEncoding];
NSMutableDictionary *jsonResponse = [self.responseData objectFromJSONData];
NSMutableDictionary *newData = [[NSMutableDictionary alloc] init];
[newData addEntriesFromDictionary:[jsonResponse mutableCopy]];
When i do this i am getting this error:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSMutableDictionary addEntriesFromDictionary:]: dictionary argument is not an NSDictionary'
I am trying to figure out what is causing this problem. I know that jsonResponse is an object of JKArray from my other experience.
I need help.
Thanks.
Try the following:
id object = [self.responseData objectFromJSONData];
NSLog(#"%#", [object class]);
Most likely your response is an array instead of a dictionary.
If you really want to convert the array into a dictionary, you could do something like this, using a self-defined key:
NSArray *array = [self.responseData objectFromJSONData];
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObject:array forKey:#"posts"];
Though perhaps there are some better options if you could show me the contents of your array.

NSdata length crash on device

While running this code:
NSData *archivedSavedData = [[NSData alloc] init];
archivedSavedData = [defaults objectForKey:#"listOfAccessNumbers"];
NSLog(#"archivedSavedData length is %d", [archivedSavedData length] );
I am getting this crash error (last line) only when running on a device that is connected:
[__NSCFArray length]: unrecognized selector sent to instance 0x2398a0
2012-03-13 20:25:33.088[7301:707] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFArray length]: unrecognized selector sent to instance 0x2398a0'
* First throw call stack:
(0x34dbc88f 0x361e3259 0x34dbfa9b 0x34dbe915 0x34d19650 0xccb1b 0x31e13e33 0x31e38629 0x31dfcd7d 0x31ebf4dd 0x31e0555d 0x31e05579 0x31e0540b 0x31e053e7 0xcfedf 0x31e12e53 0x31e0c985 0x31ddac6b 0x31dda70f 0x31dda0e3 0x3600f22b 0x34d90523 0x34d904c5 0x34d8f313 0x34d124a5 0x34d1236d 0x31e0ba13 0x31e08e7d 0xcfd39 0xcbe28)
terminate called throwing an exception
This doesn't happen when running on the simulator or directly on the device with a distribution profile (through testflight for example).
Does anyone know how such a behavior could happen only in this case?
Thanks.
UPDATE: when trying to replace length with count I get this complication error: "No visible #interface for 'NSData' declares the selector 'count'"
UPDATE2: I understand that it should be an NSArray rather than an NSData, but my problem is that I did store archived NSData cause my array consists of custom objects, so I had to archived this data into NSData format when saving in NSUserDefault. How else should I approach that otherwise?
Thats how I store the data:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:array];
[defaults setObject:data forKey:#"listOfAccessNumbers"];
array is an array of custom objects of the form of:
#interface NumberDataObj : NSObject {
NSString *inputName;
NSString *inputNum;
}
The error message says:
-[__NSCFArray length]: unrecognized selector sent to instance
That means that archivedSavedData is an array and that it doesn't (obviously) respond to length so you should declare archivedSavedData as an array and use count instead.
NSArray *archivedSavedData = [defaults objectForKey:#"listOfAccessNumbers"];
NSLog(#"archivedSavedData length is %d", [archivedSavedData count]);
Now, as to why this doesn't happen when running on the simulator, my guess is that your test scenarios don't make this part of the code get called.
EDIT
If you want to retrieve the data as NSData then use the method dataForKey:
NSData *archivedSavedData = [defaults dataForKey:#"listOfAccessNumbers"];
NSLog(#"archivedSavedData length is %d", [archivedSavedData length]);
The documentation says for dataForKey:
Return Value
The data object associated with the specified key, or nil if the key does not exist or its value is not an NSData object.
and for arrayForkey:
Return Value
The array associated with the specified key, or nil if the key does not exist or its value is not an NSArray object.
So aways use the appropriate method when you know the type of the data to avoid problems like this.
You have two problems as the code is written:
1) You allocate a variable called archivedSavedData that you reassign on the following line without releasing. This is okay if you are working with ARC, but the first line would then be unnecessary.
2) The second problem is that the object corresponding to the key #"listOfAccessNumbers" stored in your defaults object is of type NSArray. NSArray responds to the selector count, not length. Maybe you should look more closely at this object and recode accordingly.
Hope this helps :)
It's because [defaults objectForKey:#"listOfAccessNumbers"] returns an NSArray, not an NSData object.

core data in a ios static library

I created a static library for iOS. The library uses core data to store some objects fetched from the internet.
When I try to use my library in a standard iOS project, it seems like it can't create any instances of core data entities. I have the following error :
-[NSManagedObject initWithDictionary:]: unrecognized selector sent to instance 0x6e5d4e0
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSManagedObject initWithDictionary:]: unrecognized selector sent to instance 0x6e5d4e0'
initWithDictionary is actually a method I call on a core data entity object.
Then I tried to create the managed object model out of the library like shown here : core data in a static library for the iPhone
NSMutableSet *allBundles = [[[NSMutableSet alloc] init] autorelease];
[allBundles addObjectsFromArray: [NSBundle allBundles]];
[allBundles addObjectsFromArray: [NSBundle allFrameworks]];
managedObjectModel = [NSManagedObjectModel mergedModelFromBundles: [allBundles allObjects]];
OR
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:#"Model" withExtension:#"momd"];
managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
but it didn't work. I have the following error when I try to instantiate a class of my library giving it the managed object model :
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[LauncherViewController initWithNibName:managedObjectModel:andKey:]: unrecognized selector sent to instance 0x6b94db0'
If I try this : core data in a static library for the iPhone , I get this error :
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil'
Please help me, I really don't know what to do anymore...

How do I archive two objects using NSKeyedArchiever?

Previously, I have an array in which I use NSKeyedArchiver to archieve.
[NSKeyedArchiver archiveRootObject:array toFile:docPath];
Called on applicationWillTerminate and applicationDidEnterBackground.
Upon starting up, in didFinishLaunchingWithOPtions, the array is unarchieved:
NSMutableArray *array = [NSKeyedUnarchiver unarchiveObjectWithFile:docPath];
Everything was good. Since then, I added a Singleton class for Settings variables. I would like to archive the Singleton as well. How would I do that?
The part that confuses me is if I call the same message:
[NSKeyedArchiver archiveRootObject:singleton toFile:docPath];
How can the app know which object I want to unarchive when I call:
[NSKeyedUnarchiver unarchiveObjectWithFile:docPath];
Is it the array or the singleton?
The archiveRootObject accepts an (id) which to me means whatever I want. I can create a data class which includes the array and the singleton. Is that how I am suppose to do this? Is there a better way? Any suggestions are welcomed.
Thanks!
If you want to encode more than one object at the root level, you'll need to create the archiver using +alloc and -initForWritingWithMutableData: yourself, send it -encodeObject:forKey: messages for each of the objects you want to add to the archive, and finally -finishEncoding. You can then write the data to a file yourself.
It'll look something like this (warning: untested code ahead):
NSMutableData *data = [NSMutableData data];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
[archiver encodeObject:someObject forKey:#"people"];
[archiver encodeObject:anotherObject forKey:#"places"];
[archiver encodeObject:thirdObject forKey:#"things"];
[archiver finishEncoding];
[data writeToURL:someUrl atomically:YES];
[archiver release];
To retrieve the objects, you'll do essentially the opposite: read a file into an NSData object; create an NSKeyedUnarchiver with +alloc and -initForReadingWithData:; retrieve the objects you care about using -decodeObjectForKey:; and finally call -finishDecoding. You can almost read the sample above from bottom to top with a few name changes.
To be archivable, your singleton class must conform to the NSCoding protocol. You will have to implement its initWithCoder: and encodeWithCoder: methods.
Again if you do archiveRootObject:toFile: on two objects with the same file path then you will overwrite one of them. To encode two objects, you will have to do something like this,
NSData * data = [NSMutableData data];
NSKeyedArchiver * archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
[archiver encodeObject:array forKey:#"Array"];
[archiver encodeObject:singleton forKey:#"Singleton"];
[archiver finishEncoding];
BOOL result = [data writeToFile:filePath atomically:YES];
[archiver release];
You can read more on archiving in this guide.