NSUserDefaults not saving complete Object - ios

I'm having some troubles I've never encountered while using NSUserDefaults.
I have a custom class object which I use to parse an API's response into. This class conforms to NSCoding and implements both initWithCoder and encodeWithCoder.
In the SiteGroup.h file:
#interface SiteGroup : NSObject <NSCoding>
#property (nonatomic, assign) int SiteGroupID;
#property (nonatomic, assign) int StatusID;
#property (nonatomic, copy) NSString *StatusDesc;
#property (nonatomic, copy) NSString *SiteGroupName;
#property (nonatomic, copy) NSString *City;
#property (nonatomic, copy) NSString *State;
#property (nonatomic) Country *SiteGroupCountry;
#property (nonatomic, copy) NSString *LocalConference;
#property (nonatomic, copy) NSString *Address;
#property (nonatomic, copy) NSString *ClosestAirport;
#property (nonatomic, copy) NSString *Coordinates;
#property (nonatomic, copy) NSString *Latitude;
#property (nonatomic, copy) NSString *Longitude;
#property (nonatomic, copy) NSString *Altitude;
#property (nonatomic, copy) NSString *Accuracy;
#property (nonatomic, copy) NSArray *SiteGroupEvents;
#property (nonatomic, copy) NSArray *Sites;
And in the SiteGroup.m file:
- (id)initWithCoder:(NSCoder *)decoder {
self = [super init];
if (!self) {
return nil;
}
self.SiteGroupID = [decoder decodeIntForKey:#"SiteGroupID"];
self.SiteGroupName = [decoder decodeObjectForKey:#"SiteGroupName"];
self.City = [decoder decodeObjectForKey:#"City"];
self.State = [decoder decodeObjectForKey:#"State"];
self.SiteGroupCountry = [decoder decodeObjectForKey:#"SiteGroupCountry"];
self.LocalConference = [decoder decodeObjectForKey:#"LocalConference"];
self.Address = [decoder decodeObjectForKey:#"Address"];
self.ClosestAirport = [decoder decodeObjectForKey:#"ClosestAirport"];
self.Coordinates = [decoder decodeObjectForKey:#"Coordinates"];
self.Latitude = [decoder decodeObjectForKey:#"Latitude"];
self.Longitude = [decoder decodeObjectForKey:#"Longitude"];
self.Altitude = [decoder decodeObjectForKey:#"Altitude"];
self.Accuracy = [decoder decodeObjectForKey:#"Accuracy"];
self.SiteGroupEvents = [decoder decodeObjectForKey:#"SiteGroupEvents"];
self.Sites = [decoder decodeObjectForKey:#"Sites"];
self.StatusID = [decoder decodeIntForKey:#"StatusID"];
self.StatusDesc = [decoder decodeObjectForKey:#"StatusDesc"];
return self;
}
- (void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeInt:self.SiteGroupID forKey:#"SiteGroupID"];
[encoder encodeObject:self.SiteGroupName forKey:#"SiteGroupName"];
[encoder encodeObject:self.City forKey:#"City"];
[encoder encodeObject:self.State forKey:#"State"];
[encoder encodeObject:self.SiteGroupCountry forKey:#"SiteGroupCountry"];
[encoder encodeObject:self.LocalConference forKey:#"LocalConference"];
[encoder encodeObject:self.Address forKey:#"Address"];
[encoder encodeObject:self.ClosestAirport forKey:#"ClosestAirport"];
[encoder encodeObject:self.Coordinates forKey:#"Coordinates"];
[encoder encodeObject:self.Altitude forKey:#"Altitude"];
[encoder encodeObject:self.Accuracy forKey:#"Accuracy"];
[encoder encodeObject:self.SiteGroupEvents forKey:#"SiteGroupEvents"];
[encoder encodeObject:self.Sites forKey:#"Sites"];
[encoder encodeInt:self.StatusID forKey:#"statusID"];
[encoder encodeObject:self.StatusDesc forKey:#"statusDesc"];
}
Once I'm done parsing it it gets added to a NSMutableArray. I then check to see if the size of that array is more than 0, and if is, I store it into NSUserDefaults.
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:[NSArray arrayWithArray:tempSiteGroupList]];
[userDefaults setObject:data forKey:#"SiteGroupArray"];
[userDefaults setObject:[NSKeyedArchiver archivedDataWithRootObject:tempSiteGroup] forKey:#"SiteGroup"];
[userDefaults synchronize];
The array does get saved into NSUserDefaults, but the weird thing is that not all the properties of my custom class get saved, some do, others don't.
Here's the code I use to bring back the array for NSUserDefaults:
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults synchronize];
NSData *data = [userDefaults objectForKey:#"SiteGroupArray"];
NSArray *myArray = [NSKeyedUnarchiver unarchiveObjectWithData:data];
return myArray;
The StatusID, StatusDesc, Latitude, Longitude, and SiteGroupID aren't being saved, even though some of the other properties are fine.
Thanks for your help, I've never encountered this, maybe I've just been doing things wrong the whole time.

The code you've shown doesn't encode Latitude and Longitude...

StatusID and StatusDesc have different keys (#"StatusID" for decode #"statusID" for encode, same is valid for StatusDesc) for decoding and encoding, at the same time as CRD stated you don't encode and decode Latitude and Longitude.

Related

How could I encode an Objective C object instance as a string?

I know there are various ways of archiving objects in objective-c, but is there some way which I can use to turn an object in Objective-C into a string which I can store in a txt file (amongst other data) and then extract from the file to recreate the same object instance again efficiently?
Thanks in advance
It's not recommended to do this.
Why don't you save the object into NSDefaults and extract if from there whenever you want? It's very simple and efficient.
Here is an example.
Let's say you have a User object defined as below
User.h
#interface User : NSObject
#property (nonatomic, strong) NSNumber *id;
#property (nonatomic, strong) NSString *first_name;
#property (nonatomic, strong) NSString *last_name;
#end
User.m
#import "User.h"
#implementation User
-(void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:id forKey:#"id"];
[encoder encodeObject:first_name forKey:#"first_name"];
[encoder encodeObject:last_name forKey:#"last_name"];
}
-(id)initWithCoder:(NSCoder *)decoder {
if (self = [super init]) {
self.id = [decoder decodeObjectForKey:#"id"];
self.first_name = [decoder decodeObjectForKey:#"first_name"];
self.last_name = [decoder decodeObjectForKey:#"last_name"];
}
}
- (id)initWith:(User *)obj {
if (self = [super init]) {
self.id = obj.id;
self.first_name = obj.first_name;
self.last_name = obj.last_name;
}
}
#end
Whenever you want to save the object, you can do something like that
//Save the user object
User *user = [[User alloc] init];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:user];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:data forKey:#"YOUR_KEY"];
[defaults synchronize];
//Get the user object
NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:#"YOUR_KEY"];
User *user = [[User alloc] initWith:[NSKeyedUnarchiver unarchiveObjectWithData:data]];

NSUserdefaults not working with NSKeyedArchiver

I have a NSMutableArray filled with objects of my Movie class wich i want to save but it doesn't work and i can not figure out why...
Movie.h:
#interface Movie : NSObject <NSCoding>{
NSString *name;
int year;
int length;
NSString *file_size;
int rating;
NSArray *genre;
NSString *plot;
}
#property (nonatomic, retain) NSString *name;
#property (nonatomic, assign) int year;
#property (nonatomic, assign) int length;
#property (nonatomic, retain, retain) NSString *file_size;
#property (nonatomic, assign) int rating;
#property (nonatomic, retain) NSArray *genre;
#property (nonatomic, retain) NSString *plot;
-(id) initWithName:(NSString*)newName year:(int)newYear length:(int)newLength filesize:(NSString*)newFileSize rating:(int)newRating genre:(NSArray*)newGenre plot:(NSString*)newPlot;
- (void) encodeWithCoder : (NSCoder *)encode ;
- (id) initWithCoder : (NSCoder *)decode;
#end
Movie.m:
#implementation Movie
#synthesize name;
#synthesize year;
#synthesize length;
#synthesize file_size;
#synthesize rating;
#synthesize genre;
#synthesize plot;
-(id)initWithName:(NSString *)newName year:(int)newYear length:(int)newLength filesize:(NSString *)newFileSize rating:(int)newRating genre:(NSArray *)newGenre plot:(NSString *)newPlot{
self.name = newName;
self.year = newYear;
self.length = newLength;
self.file_size = newFileSize;
self.rating = newRating;
self.genre = newGenre;
self.plot = newPlot;
return self;
}
- (void)encodeWithCoder:(NSCoder *)encode;
{
[encode encodeObject:name forKey:#"name"];
[encode encodeInt32:year forKey:#"year"];
[encode encodeInt32:length forKey:#"length"];
[encode encodeObject:file_size forKey:#"file_size"];
[encode encodeInt32:rating forKey:#"rating"];
[encode encodeObject:genre forKey:#"genre"];
[encode encodeObject:plot forKey:#"plot"];
}
- (id)initWithCoder:(NSCoder *)decode;
{
NSString *name_decode = [decode decodeObjectForKey:#"name"];
int year_decode = [decode decodeInt32ForKey:#"year"];
int length_decode = [decode decodeInt32ForKey:#"length"];
NSString *file_size_decode = [decode decodeObjectForKey:#"file_size"];
int rating_decode = [decode decodeInt32ForKey:#"rating"];
NSArray *genre_decode = [decode decodeObjectForKey:#"genre"];
NSString *plot_decode =[decode decodeObjectForKey:#"plot"];
return [self initWithName:name_decode year:year_decode length:length_decode filesize:file_size_decode rating:rating_decode genre:genre_decode plot:plot_decode];
}
#end
Save Action (Movies is the NSMutableArray containing my Objects):
NSUserDefaults *userDefault=[NSUserDefaults standardUserDefaults];
NSData *encodedData = [NSKeyedArchiver archivedDataWithRootObject:Movies];
[userDefault setObject:encodedData forKey:[NSString stringWithFormat:#"MOVIES"]];
Load Action:
NSData *decodedData = [userDefault objectForKey: [NSString stringWithFormat:#"MOVIES"]];
NSArray *decodedArray =[NSKeyedUnarchiver unarchiveObjectWithData: decodedData];
The returned Array is always (null)... i have no clue
I tried several different kind of code snippets i found on the internet and/or stackoverflow
Your Movie initWithName... method is incorrect. It needs to be:
- (instancetype)initWithName:(NSString *)newName year:(int)newYear length:(int)newLength filesize:(NSString *)newFileSize rating:(int)newRating genre:(NSArray *)newGenre plot:(NSString *)newPlot {
self = [super init];
if (self) {
self.name = newName;
self.year = newYear;
self.length = newLength;
self.file_size = newFileSize;
self.rating = newRating;
self.genre = newGenre;
self.plot = newPlot;
}
return self;
}
Also, you seem to be following a very out-of-date tutorial.
You don't need to declare the ivars for your properties.
You don't need the calls to #synthesize.
You should be using ARC instead of MRC, Therefore your retain properties should be strong (thought the NSString properties should be copy.
Your init methods should return instancetype, not id.
With all of that in mind, your Movie class should be as follows:
Movie.h
#interface Movie : NSObject <NSCoding>
#property (nonatomic, copy) NSString *name;
#property (nonatomic, assign) int year;
#property (nonatomic, assign) int length;
#property (nonatomic, copy) NSString *file_size;
#property (nonatomic, assign) int rating;
#property (nonatomic, strong) NSArray *genre;
#property (nonatomic, copy) NSString *plot;
- (instancetype)initWithName:(NSString *)newName year:(int)newYear length:(int)newLength filesize:(NSString *)newFileSize rating:(int)newRating genre:(NSArray *)newGenre plot:(NSString *)newPlot;
#end
Movie.m
#implementation Movie
- (instancetype)initWithName:(NSString *)newName year:(int)newYear length:(int)newLength filesize:(NSString *)newFileSize rating:(int)newRating genre:(NSArray *)newGenre plot:(NSString *)newPlot {
self = [super init];
if (self) {
_name = newName;
_year = newYear;
_length = newLength;
_file_size = newFileSize;
_rating = newRating;
_genre = newGenre;
_plot = newPlot;
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)encode;
{
[encode encodeObject:self.name forKey:#"name"];
[encode encodeInt32:self.year forKey:#"year"];
[encode encodeInt32:self.length forKey:#"length"];
[encode encodeObject:self.file_size forKey:#"file_size"];
[encode encodeInt32:self.rating forKey:#"rating"];
[encode encodeObject:self.genre forKey:#"genre"];
[encode encodeObject:self.plot forKey:#"plot"];
}
- (instancetype)initWithCoder:(NSCoder *)decode;
{
NSString *name_decode = [decode decodeObjectForKey:#"name"];
int year_decode = [decode decodeInt32ForKey:#"year"];
int length_decode = [decode decodeInt32ForKey:#"length"];
NSString *file_size_decode = [decode decodeObjectForKey:#"file_size"];
int rating_decode = [decode decodeInt32ForKey:#"rating"];
NSArray *genre_decode = [decode decodeObjectForKey:#"genre"];
NSString *plot_decode =[decode decodeObjectForKey:#"plot"];
return [self initWithName:name_decode year:year_decode length:length_decode filesize:file_size_decode rating:rating_decode genre:genre_decode plot:plot_decode];
}
#end
You don't show how you create and populate your Movies variable (which should be named movies, not Movies. Make sure it isn't nil.
Also, don't needlessly use stringWithFormat.
Your saving code should be:
NSUserDefaults *userDefault=[NSUserDefaults standardUserDefaults];
NSData *encodedData = [NSKeyedArchiver archivedDataWithRootObject:movies];
[userDefault setObject:encodedData forKey:#"MOVIES"];
and your loading code should be:
NSData *decodedData = [userDefault objectForKey:#"MOVIES"];
NSArray *decodedArray = [NSKeyedUnarchiver unarchiveObjectWithData: decodedData];
A quick test is to see if the mutable array is actually not nil itself. Try outputting the mutable array before setting it in userDefaults.
Make sure the mutable array is initialized before trying to add objects to it.
movies = [[NSMutableArray alloc] init];

Saving NSDictionary (with custom classes) to NSUserDefaults [duplicate]

This question already has answers here:
How to store custom objects in NSUserDefaults
(7 answers)
Closed 9 years ago.
I am trying to save an NSDictionary to my NSUserDefualts.
The dictionary consists of 3 different custom classes.
#interface PastOrder : NSObject <NSCoding>
{
NSDate *timeIn;
NSDate *timeOut;
NSString *status;
NSMutableArray *myItems;
}
#property (nonatomic, retain) NSDate *timeIn;
#property (nonatomic, retain) NSDate *timeOut;
#property (nonatomic, retain) NSString *status;
#property (nonatomic, retain) NSMutableArray *myItems;
#end
#implementation PastOrder
#synthesize timeIn, timeOut, status, myItems;
#define PastOrderTimeInKey #"PastOrderTimeInKey"
#define PastOrderTimeOutKey #"PastOrderTimeOutKey"
#define PastOrderStatusKey #"PastOrderStatusKey"
#define PastOrderMyItemsKey #"PastOrderMyItemsKey"
-(id)initWithCoder:(NSCoder*)decoder
{
self = [super init];
if(self)
{
self.timeIn = [decoder decodeObjectForKey:PastOrderTimeInKey];
self.timeOut = [decoder decodeObjectForKey:PastOrderTimeOutKey];
self.status = [decoder decodeObjectForKey:PastOrderStatusKey];
self.myItems = [decoder decodeObjectForKey:PastOrderMyItemsKey];
}
return self;
}
-(void)encodeWithCoder:(NSCoder*)encoder
{
[encoder encodeObject:self.timeIn forKey:PastOrderTimeInKey];
[encoder encodeObject:self.timeOut forKey:PastOrderTimeOutKey];
[encoder encodeObject:self.status forKey:PastOrderStatusKey];
[encoder encodeObject:self.myItems forKey:PastOrderMyItemsKey];
}
-(void)dealloc
{
self.timeIn = nil;
self.timeOut = nil;
self.status = nil;
self.myItems = nil;
}
#end
#interface PastOrderItem : NSObject <NSCoding>
{
NSNumber *itemID;
NSString *status;
NSMutableArray *itemChoices;
}
#property (nonatomic, retain) NSNumber *itemID;
#property (nonatomic, retain) NSString *status;
#property (nonatomic, retain) NSMutableArray *itemChoices;
#end
#implementation PastOrderItem
#synthesize itemID,status,itemChoices;
#define PastOrderItemItemIDKey #"PastOrderItemItemIDKey"
#define PastOrderItemStatusKey #"PastOrderItemStatusKey"
#define PastOrderItemItemChoicesKey #"PastOrderItemItemChoicesKey"
-(id)initWithCoder:(NSCoder*)decoder
{
self = [super init];
if(self)
{
self.itemID = [decoder decodeObjectForKey:PastOrderItemItemIDKey];
self.itemChoices = [decoder decodeObjectForKey:PastOrderItemItemChoicesKey];
self.status = [decoder decodeObjectForKey:PastOrderItemStatusKey];
}
return self;
}
-(void)encodeWithCoder:(NSCoder*)encoder
{
[encoder encodeObject:self.itemID forKey:PastOrderItemItemIDKey];
[encoder encodeObject:self.itemChoices forKey:PastOrderItemItemChoicesKey];
[encoder encodeObject:self.status forKey:PastOrderItemStatusKey];
}
-(void)dealloc
{
self.itemID = nil;
self.itemChoices = nil;
self.status = nil;
}
#end
#interface PastOrderItemChoice : NSObject <NSCoding>
{
NSNumber *modifierID;
NSNumber *modifierChoice;
}
#property (nonatomic, retain) NSNumber *modifierID;
#property (nonatomic, retain) NSNumber *modifierChoice;
#end
#implementation PastOrderItemChoice
#synthesize modifierID, modifierChoice;
#define PastOrderItemChoiceModifierIDKey #"PastOrderItemChoiceModifierIDKey"
#define PastOrderItemChoiceModifierChoiceKey #"PastOrderItemChoiceModifierChoiceKey"
-(id)initWithCoder:(NSCoder*)decoder
{
self = [super init];
if(self)
{
self.modifierID = [decoder decodeObjectForKey:PastOrderItemChoiceModifierIDKey];
self.modifierChoice = [decoder decodeObjectForKey:PastOrderItemChoiceModifierChoiceKey];
}
return self;
}
-(void)encodeWithCoder:(NSCoder*)encoder
{
[encoder encodeObject:self.modifierID forKey:PastOrderItemChoiceModifierIDKey];
[encoder encodeObject:self.modifierChoice forKey:PastOrderItemChoiceModifierChoiceKey];
}
-(void)dealloc
{
self.modifierID = nil;
self.modifierChoice = nil;
}
#end
Those are the three classes that will be inside this NSDictionary.
Here is how I Load and Save it.
-(void)SavePrefs
{
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
NSData* data=[NSKeyedArchiver archivedDataWithRootObject:self.myDictionary];
[prefs setObject:data forKey:#"SavedOrders"];
[prefs synchronize];
}
- (id)init
{
self = [super init];
if (self)
{
NSData* data = [[NSUserDefaults standardUserDefaults] objectForKey:#"SavedOrders"];
self.myDictionary = [NSKeyedUnarchiver unarchiveObjectWithData:data];
}
return self;
}
I have experimented with the code a bit, and best I have to far, is that when I save the dictionary, it was 135 bytes, same as when I loaded it, but it still didnt fill the dictionary up. So I am at a loss.
Your code seems to be good. I can't find a mistake so try to change line:
self.myDictionary = [NSKeyedUnarchiver unarchiveObjectWithData:data];
to
id unknownObject = [NSKeyedUnarchiver unarchiveObjectWithData:data];
NSLog(#"%#",[unknownObject class]);
And look # the console. Maybe you should also try casting if the output will be dictionary. So try to change this to:
self.myDictionary = (NSDictionary*)[NSKeyedUnarchiver unarchiveObjectWithData:data];
EDIT
NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:#"object1",#"key1",#"object2",#"key2",#"object3",#"key3", nil];
NSLog(#"before: %#",dictionary);
NSData *myData = [NSKeyedArchiver archivedDataWithRootObject:dictionary];
NSDictionary *myDictionary = (NSDictionary*) [NSKeyedUnarchiver unarchiveObjectWithData:myData];
NSLog(#"after: %#",myDictionary);
Output:
2013-11-13 14:32:31.369 DemoM[175:60b] before: {
key1 = object1;
key2 = object2;
key3 = object3;
}
2013-11-13 14:32:31.372 DemoM[175:60b] after: {
key1 = object1;
key2 = object2;
key3 = object3;
}

Serialize custom object to JSON which contains NSMutableArray

I'm trying to serialize my Cart object which has an NSMutableArray of items in it but getting an:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Invalid type in JSON write (Item)'
If I'm understanding how this is supposed to work, I need to create an Array of Dictionaries in order for NSJSONSerialization to work correctly. Is that not what I am doing below?
My Cart.h:
#interface Cart : BaseObject
#property (nonatomic, strong) NSString *comp;
#property (nonatomic, strong) NSString *sono;
#property (nonatomic, strong) NSString *cust;
#property (nonatomic, strong) NSString *scus;
#property (nonatomic, strong) NSString *cnid;
#property (nonatomic, strong) NSString *dldt;
#property (nonatomic, strong) NSString *whse;
#property (nonatomic, strong) NSString *pono;
#property (nonatomic, strong) NSString *pon2;
#property (nonatomic, strong) NSString *emad;
#property (nonatomic, strong) NSString *pkin;
#property (nonatomic, strong) NSString *comt;
#property (nonatomic, strong) NSString *rtin;
#property (nonatomic, strong) NSString *lbfg;
#property (nonatomic, strong) NSString *containsOpenPriced;
#property (nonatomic, strong) NSString *totalProductAmount;
#property (nonatomic, strong) NSMutableArray *items;
#property (nonatomic) BOOL *isSubmitting;
#end
My Cart.m:
#implementation Cart
#synthesize comp;
#synthesize sono;
#synthesize cust;
#synthesize scus;
#synthesize cnid;
#synthesize dldt;
#synthesize whse;
#synthesize pono;
#synthesize pon2;
#synthesize emad;
#synthesize pkin;
#synthesize comt;
#synthesize rtin;
#synthesize lbfg;
#synthesize containsOpenPriced;
#synthesize totalProductAmount;
#synthesize items;
- (id) initWithDictionary:(NSDictionary *)dictionary {
self = [super init];
if (self) {
self.comp = dictionary[#"comp"];
self.sono = dictionary[#"sono"];
self.cust = dictionary[#"cust"];
self.scus = dictionary[#"scus"];
self.cnid = dictionary[#"cnid"];
self.dldt = dictionary[#"dldt"];
self.whse = dictionary[#"whse"];
self.pono = dictionary[#"pono"];
self.pon2 = dictionary[#"pon2"];
self.emad = dictionary[#"emad"];
self.pkin = dictionary[#"pkin"];
self.comt = dictionary[#"comt"];
self.rtin = dictionary[#"rtin"];
self.lbfg = dictionary[#"lbfg"];
self.containsOpenPriced = dictionary[#"containsOpenPriced"];
self.totalProductAmount = dictionary[#"totalProductAmount"];
NSArray *itemsArray = dictionary[#"items"];
NSMutableArray *itemsMutableArray = [[NSMutableArray alloc]init];
for (NSDictionary *itemDictionary in itemsArray) {
Item *item = [[Item alloc] initWithDictionary:itemDictionary];
[itemsMutableArray addObject:item];
}
self.items = itemsMutableArray;
}
return self;
}
#end
My code for serializing my object:
NSMutableArray *itemsToSerialize = [[NSMutableArray alloc] init];
for (Item *item in cart.items) {
NSMutableDictionary *itemDict = [[NSMutableDictionary alloc] init];
[itemDict setObject:item forKey:#"item"];
[itemsToSerialize addObject:item];
}
NSMutableDictionary *data = [#{
#"comp" : cart.comp,
#"rtin" : cart.rtin,
#"pono" : cart.pono,
#"pon2" : cart.pon2,
#"totalProductAmount" : totalProductAmount,
#"sono" : cart.sono,
#"emad" : cart.emad,
#"lbfg" : lbfg,
#"pkin" : cart.pkin,
#"containsOpenPriced" : containsOpenPriced,
#"cnid" : cart.cnid,
#"whse" : cart.whse,
#"scus" : cart.scus,
#"dldt" : cart.dldt,
#"cust" : cart.cust,
#"comt" : cart.comt,
#"items": itemsToSerialize
} mutableCopy];
NSString *command = #"shoppingCart.update";
NSMutableDictionary *request = [#{
#"command" : command,
#"comp" : cart.comp,
#"cnid" : sessionController.operator.cnid,
#"cust" : cart.cust,
#"data" : data
} mutableCopy];
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:request options:kNilOptions error:nil];
This dies on the above NSJSONSerialization line. What am I missing?
This line: [itemsToSerialize addObject:item]; should be [itemsToSerialize addObject:itemDict];. The result is that you're trying to serialize an array of the items themselves, which gives the exception you're seeing.
NSJSONSerialization only works on arrays (NSArray or NSMutableArray), dictionaries (NSDictionary or NSMutableDictionary, strings (NSString or NSMutableString), and NSNumber.
The common mechanism is to create a - (NSDictionary *)serialize method on your class that copies all its values into a dictionary to be passed into NSJSONSerialization. Then implement - (id)initFromSerialization:(NSDictionary *)serialization to deserialize the object.
I know this is kinda late but maybe this class can ease your coding:
Its a class that transform Custom NSObject to JSON readable object(NSArray or NSDictionary). Have a try and see. It has the capability to skip properties and changed property type from string to NSInteger or Float, it can also changed the final output property name lets say
CustomObject *X;
X.property1 = #"Test";
//and the output JSON readable format you want tot change X to Y
//CustomObject converted to readable format
{Y = #"Test"}
here is the class Disassembler

Exception - Custom class initWithCoder unrecognized selector sent to instance in iPhone

I have an entity class which inherits NSObject that holds some data, and class name is "MessageDetails". i.e
MessageDetails.h Class-
#import <Foundation/Foundation.h>
#interface MessageDetails : NSObject
#property (nonatomic, retain) NSString *userImage;
#property (nonatomic, retain) NSString *userName;
#property (nonatomic, retain) NSString *message;
#property (nonatomic, retain) NSString *dateString;
#end
MessageDetails.m Class-
#import "MessageDetails.h"
#implementation MessageDetails
#synthesize userImage, userName, message, dateString;
- (id)initWithCoder:(NSCoder *)decoder {
if((self = [super init])) {
self.userImage = [decoder decodeObjectForKey:#"userImage"];
self.userName = [decoder decodeObjectForKey:#"userName"];
self.message = [decoder decodeObjectForKey:#"message"];
self.dateString = [decoder decodeObjectForKey:#"dateString"];
}
return self;
}
- (void)encodeWithCoder: (NSCoder *)coder
{
[coder encodeObject:userImage forKey:#"userImage"];
[coder encodeObject:userName forKey:#"userName"];
[coder encodeObject:message forKey:#"message"];
[coder encodeObject:dateString forKey:#"dateString"];
}
#end
In my View Controller class, I am sending some messages to Recipent .After sending successfully message, i am storing some values to "MessageDetails" class objects like userImage, userName, message and dateString, that i have to show in another class table view. So i am setting messageDetails object value successfully using NSUserDefault using this code..
NSMutableArray *finalArray=[[NSMutableArray alloc]init];
NSMutableArray *array=[[NSMutableArray alloc]init];
array= [Util getArrayPreference:#"MessageDetails"];
if (array) {
[finalArray addObjectsFromArray:array];
}
[finalArray addObject:messageDetails];
[Util setArrayPreference:finalArray forKey:#"MessageDetails"];
//For setting preferences
+(void)setPreference:(MessageDetails *)product forKey:(NSString *)key
{
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
NSData *myEncodedObject = [NSKeyedArchiver archivedDataWithRootObject:product];
[prefs setObject:myEncodedObject forKey:key];
[prefs synchronize];
}
+(void)setArrayPreference:(NSMutableArray *)products forKey:(NSString *)string
{
for (int i=0; i<products.count; i++) {
MessageDetails *po=[products objectAtIndex:i];
NSString *st=[NSString stringWithFormat:#"%d",i];
[Util setPreference:po forKey:st];
}
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
NSData *myEncodedObject = [NSKeyedArchiver archivedDataWithRootObject:products];
[prefs setObject:myEncodedObject forKey:string];
[prefs synchronize];
}
//For getting preferences
+(MessageDetails *)getPreference:(NSString *)key
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *myEncodedObject1 = [defaults objectForKey:key];
MessageDetails *obj = (MessageDetails *)[NSKeyedUnarchiver unarchiveObjectWithData: myEncodedObject1];
return obj;
}
+(NSMutableArray *)getArrayPreference:(NSString *)string
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *myEncodedObject1 = [defaults objectForKey:string];
NSMutableArray *arr1=[[NSMutableArray alloc]init];
NSMutableArray *arr=(NSMutableArray *) [NSKeyedUnarchiver unarchiveObjectWithData: myEncodedObject1];
for (int i=0;i<arr.count;i++) {
NSString *st=[NSString stringWithFormat:#"%d",i];
[arr1 addObject:[Util getPreference:st]];
}
return arr;
}
But my problem is when i am calling getArrayPreference method then after
NSMutableArray *arr=(NSMutableArray *) [NSKeyedUnarchiver unarchiveObjectWithData: myEncodedObject1];
this line it is crashing. And an Exception that i am getting is
2013-08-25 12:32:22.802 SmsIndia[551:1d003] -[MessageDetails initWithCoder:]: unrecognized selector sent to instance 0xae68160****
2013-08-25 12:32:22.802 SmsIndia[551:1d003] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[MessageDetails initWithCoder:]: unrecognized selector sent to instance 0xae68160'**
I'm doing something wrong but I'm not sure what. Any help would be greatly appreciated ..., thank you!
If someone have any doubt related to question then let me know.

Resources