Troubles storing and loading custom object into NSUserDefaults Objective-C - ios

I've been trying to store and recover from the NSUserDefaults an Array of custom objects in my project but it seems something is going wrong. I've researched a lot about this issue but I couldn't find any answer to my problem.
It seems that the storing it's done OK because I don't get any error when saving data in NSUserDefaults, the problem comes when I try to get back those data: the app will crash completely with libc++abi.dylib: terminating with uncaught exception of type NSException error.
Here's my code:
Wine.h
#import <Foundation/Foundation.h>
#import UIKit;
#define NO_RATING -1
#interface WineModel : NSObject <NSCoding>
#property(copy, nonatomic) NSString *type;
#property(strong, nonatomic) UIImage *photo;
#property(strong, nonatomic) NSURL *photoURL;
#property(strong, nonatomic) NSURL *wineCompanyWeb;
#property(copy, nonatomic) NSString *notes;
#property(copy, nonatomic) NSString *origin;
#property(nonatomic) int rating;
#property(strong, nonatomic) NSArray *grapes;
#property(copy, nonatomic) NSString *name;
#property(copy, nonatomic) NSString *wineCompanyName;
- (id) initWithCoder: (NSCoder *) decoder;
- (void) encodeWithCoder: (NSCoder *) encoder;
//SOME OTHER METHODS...//
-(id) initWithName: (NSString *) aName
wineCompanyName: (NSString *) aWineCompanyName
type: (NSString *) aType
origin: (NSString *) anOrigin
grapes: (NSArray *) arrayOfGrapes
wineCompanyWeb: (NSURL *) aURL
notes: (NSString *) aNotes
rating: (int) aRating
photoURL: (NSURL *) aPhotoURL;
//For JSON
-(id) initWithDictionary: (NSDictionary *) aDict;
#end
Wine.m
#import "WineModel.h"
#implementation WineModel
#synthesize photo = _photo;
#pragma mark - Properties
-(UIImage *) photo {
//SOME MORE CODE...
return _photo;
}
- (id) initWithCoder:(NSCoder *)decoder {
if (self = [super init]) {
self.name = [decoder decodeObjectForKey:#"name"];
self.wineCompanyName = [decoder decodeObjectForKey:#"company"];
self.type = [decoder decodeObjectForKey:#"type"];
self.origin = [decoder decodeObjectForKey:#"origin"];
self.grapes = [self extractGrapesFromJSONArray:[decoder decodeObjectForKey:#"grapes"]];
self.wineCompanyWeb = [NSURL URLWithString:[decoder decodeObjectForKey:#"wine_web"]];
self.notes = [decoder decodeObjectForKey:#"notes"];
self.rating = [[decoder decodeObjectForKey:#"rating"] intValue];
self.photoURL = [NSURL URLWithString:[decoder decodeObjectForKey:#"picture"]];
}
return self;
}
- (void) encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:self.name forKey:#"name"];
[encoder encodeObject:self.wineCompanyWeb forKey:#"company"];
[encoder encodeObject:self.type forKey:#"type"];
[encoder encodeObject:self.origin forKey:#"origin"];
[encoder encodeObject:self.grapes forKey:#"grapes"];
[encoder encodeObject:self.wineCompanyWeb forKey:#"wine_web"];
[encoder encodeObject:self.notes forKey:#"notes"];
[encoder encodeInt:self.rating forKey:#"rating"];
[encoder encodeObject:self.photoURL forKey:#"picture"];
}
#pragma mark - Init
-(id) initWithName: (NSString *) aName
wineCompanyName: (NSString *) aWineCompanyName
type: (NSString *) aType
origin: (NSString *) anOrigin
grapes: (NSArray *) arrayOfGrapes
wineCompanyWeb: (NSURL *) aURL
notes: (NSString *) aNotes
rating: (int) aRating
photoURL: (NSURL *) aPhotoURL {
if(self==[super init]) {
_name = aName;
_wineCompanyName = aWineCompanyName;
_type = aType;
_origin = anOrigin;
_grapes = arrayOfGrapes;
_wineCompanyWeb = aURL;
_notes = aNotes;
_rating = aRating;
_photoURL = aPhotoURL;
}
return self;
}
#pragma mark - JSON
-(id) initWithDictionary:(NSDictionary *)aDict {
return [self initWithName:[aDict objectForKey:#"name"]
wineCompanyName:[aDict objectForKey:#"company"]
type:[aDict objectForKey:#"type"]
origin:[aDict objectForKey:#"origin"]
grapes:[self extractGrapesFromJSONArray:[aDict objectForKey:#"grapes"]]
wineCompanyWeb:[NSURL URLWithString:[aDict objectForKey:#"wine_web"]]
notes:[aDict objectForKey:#"notes"]
rating:[[aDict objectForKey:#"rating"]intValue]
photoURL:[NSURL URLWithString:[aDict objectForKey:#"picture"]]
];
}
-(NSArray *) extractGrapesFromJSONArray: (NSArray *)JSONArray {
//SOME MORE CODE...
return grapes;
}
#end
This is the wine class. It has the <NSCoding> protocol and both methods (id) initWithCoder: (NSCoder *) decoder; and (void) encodeWithCoder: (NSCoder *) encoder;. So far I looks OK, lets move on to the next class:
Winery.h
#import <Foundation/Foundation.h>
#import "Wine.h"
#define RED_WINE_KEY #"Red"
#define WHITE_WINE_KEY #"White"
#define OTHER_WINE_KEY #"Others"
#interface WineryModel : NSObject
#property (strong, nonatomic) NSMutableArray *redWines;
#property (strong, nonatomic) NSMutableArray *whiteWines;
#property (strong, nonatomic) NSMutableArray *otherWines;
#property(readonly, nonatomic) int redWineCount;
#property(readonly, nonatomic) int whiteWineCount;
#property(readonly, nonatomic) int otherWineCount;
-(WineModel *) redWineAtIndex: (NSUInteger) index;
-(WineModel *) whiteWineAtIndex: (NSUInteger) index;
-(WineModel *) otherWineAtIndex: (NSUInteger) index;
#end
Winery.m
#import "Winery.h"
#implementation WineryModel
#pragma mark - Properties
-(int) redWineCount {
return [self.redWines count];
}
-(int) whiteWineCount {
return [self.whiteWines count];
}
-(int) otherWineCount {
return [self.otherWines count];
}
-(id) init {
if(self == [super init]) {
NSUserDefaults *userDefault=[NSUserDefaults standardUserDefaults];
//Check if there is data stored locally
if(([[[userDefault dictionaryRepresentation] allKeys] containsObject:#"redWines"])
&&([[[userDefault dictionaryRepresentation] allKeys] containsObject:#"whiteWines"])
&&([[[userDefault dictionaryRepresentation] allKeys] containsObject:#"otherWines"])) {
if([userDefault objectForKey:#"redWines"] != nil && [userDefault objectForKey:#"whiteWines"] != nil && [userDefault objectForKey:#"otherWines"] != nil) {
//Try to load data from NSUserDefaults
NSData *decodedRedWines = [userDefault objectForKey:#"redWines"];
self.redWines = [[NSKeyedUnarchiver unarchiveObjectWithData: decodedRedWines] mutableCopy]; //IT WILL CRASH HERE
NSData *decodedWhiteWines = [userDefault objectForKey:#"whiteWines"];
self.whiteWines = [[NSKeyedUnarchiver unarchiveObjectWithData: decodedWhiteWines] mutableCopy];
NSData *decodedOtherWines = [userDefault objectForKey:#"otherWines"];
self.otherWines = [[NSKeyedUnarchiver unarchiveObjectWithData: decodedOtherWines] mutableCopy];
}
} else {
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://url.com/wines.json"]]; //JSON URL
NSURLResponse *response = [[NSURLResponse alloc]init];
NSError *error;
NSData *data = [NSURLConnection sendSynchronousRequest:request
returningResponse:&response
error:&error];
if(data != nil) { //No errors
//Passing from JSON to an NSArray
NSArray * JSONObjects = [NSJSONSerialization JSONObjectWithData:data
options:kNilOptions
error:&error];
if (JSONObjects != nil) {
//No errors
for(NSDictionary *dict in JSONObjects){
WineModel *wine = [[WineModel alloc] initWithDictionary:dict];
if(wine.name != nil && wine.wineCompanyName != nil && wine.type != nil && wine.origin != nil ) {
if ([wine.type isEqualToString:RED_WINE_KEY]) {
if (!self.redWines) {
self.redWines = [NSMutableArray arrayWithObject:wine];
}
else {
[self.redWines addObject:wine];
}
}
else if ([wine.type isEqualToString:WHITE_WINE_KEY]) {
if (!self.whiteWines) {
self.whiteWines = [NSMutableArray arrayWithObject:wine];
}
else {
[self.whiteWines addObject:wine];
}
}
else {
if (!self.otherWines) {
self.otherWines = [NSMutableArray arrayWithObject:wine];
}
else {
[self.otherWines addObject:wine];
}
}
}
}
} else {
NSLog(#"JSON parsing error: %#", error.localizedDescription);
}
} else {
NSLog(#"Server error: %#", error.localizedDescription);
}
//Storing the array of wine objects in the NSUserDefaults
NSData *encodedRedWines = [NSKeyedArchiver archivedDataWithRootObject:_redWines];
[userDefault setObject:encodedRedWines forKey:#"redWines"];
NSData *encodedWhiteWines = [NSKeyedArchiver archivedDataWithRootObject:_whiteWines];
[userDefault setObject:encodedWhiteWines forKey:#"whiteWines"];
NSData *encodedOtherWines = [NSKeyedArchiver archivedDataWithRootObject:_otherWines];
[userDefault setObject:encodedOtherWines forKey:#"otherWines"];
}
}
return self;
}
-(WineModel *) redWineAtIndex: (NSUInteger) index {
return [self.redWines objectAtIndex:index];
}
-(WineModel *) whiteWineAtIndex: (NSUInteger) index{
return [self.whiteWines objectAtIndex:index];
}
-(WineModel *) otherWineAtIndex: (NSUInteger) index{
return [self.otherWines objectAtIndex:index];
}
#end
So, the first time you launch the app it will download the data from a JSON file that is in the web, then store the info in the NSUserDefaults. It seems like this step it's done correctly (at least doesn't crash at this point). The problem comes after launching the app the second time. It will check if there are local data store under the NSUserDefault, if so, it'll try to load the data and store into an NSMutableAtray. Unfortunately it won't do so, It crashes here self.redWines =[NSKeyedUnarchiver unarchiveObjectWithData: decodedRedWines]; with the error code I wrote before. When debugging, I can see that there is data when retrieving the redWineskey, but it seems like something it's going wrong.
Mind that I'm using a customized initializer (initWithDictionary) for creating my wines object instead of the default init method. I don't know if it could be the reason of the crash...
Here's the full log:
2017-05-22 20:31:30.354640+0200 App[1905:891526] -[NSTaggedPointerString objectForKey:]: unrecognized selector sent to instance 0xa5c064950b08843b
2017-05-22 20:31:30.354932+0200 App[1905:891526] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSTaggedPointerString objectForKey:]: unrecognized selector sent to instance 0xa5c064950b08843b'
*** First throw call stack:
(0x18e0bafe0 0x18cb1c538 0x18e0c1ef4 0x18e0bef54 0x18dfbad4c 0x1000591d8 0x100057dec 0x18eb0a430 0x18eb10f10 0x18eaa684c 0x18eb0a430 0x18eb09b68 0x18eb08d94 0x100061118 0x1000621d0 0x10005c120 0x19425d204 0x194469738 0x19446f1e0 0x194483d18 0x19446c474 0x18fc63884 0x18fc636f0 0x18fc63aa0 0x18e06942c 0x18e068d9c 0x18e0669a8 0x18df96da4 0x194256384 0x194251058 0x100060b90 0x18cfa559c)
libc++abi.dylib: terminating with uncaught exception of type NSException
Any ideas??
Thanks in advance!!

There is a typo in your initWithCoder method:
self.wineCompanyName = [decoder decodeObjectForKey:#"comapny"];
If that does not fix it, I would look at the NSUserDefaults documentation more closely - it says "Values returned from NSUserDefaults are immutable, even if you set a mutable object as the value." Your redWines property is defined as an NSMutableArray.

To make an immutable object mutable just call mutableCopy
#property (strong, nonatomic) NSMutableArray *redWines;
...
self.redWines = [[NSKeyedUnarchiver unarchiveObjectWithData: decodedRedWines] mutableCopy];

Related

store NSobject data into Nsuserdefaults

In My Modal Object two values are there
I'm trying to store in NSUserDefaults. This is My Code
interface File:
#interface collectionModel : NSObject <NSCoding> {
}
#property(nonatomic,retain) NSString *name;
#property(nonatomic,retain) NSString *author;
Implementation File:
#implementation collectionModel
#synthesize name = _name;
#synthesize author = _author;
- (id)initWithCoder:(NSCoder *)aDecoder {
if (self = [super init]) {
self.name = [aDecoder decodeObjectForKey:#"name"];
self.author = [aDecoder decodeObjectForKey:#"author"];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeObject:_name forKey:#"name"];
[aCoder encodeObject:_author forKey:#"author"];
}
ViewController.M
#import "collectionModel.h"
parsedCollectionArr = [[NSMutableArray alloc] init];
for (NSDictionary *obj in collectionBalk) {
NSString * Name = [obj objectForKey:#"Name"];
NSString * author = [obj objectForKey:#"author"];
collectionModel *dataObj = [[collectionModel alloc] init];
dataObj.name = Name;
dataObj.author = author;
[parsedCollectionArr addObject:dataObj];
}
NSLog(#"parsedCollectionArr count ---->>>> %d",23);
Here I want to store this parsedCollectionArr in NSUserDefaults and retrive from it.can any one help me.
try this..
Create a class like "CollectionModelManager.h and .m"
//For Save CollectionModel
+ (void)saveCollectionModel:(CollectionModel *) collectionModel
{
NSData *encodedData = [NSKeyedArchiver archivedDataWithRootObject:collectionModel];
NSUserDefaults *userDef = [NSUserDefaults standardUserDefaults];
[userDef setObject:encodedData forKey:kCollectionModelKey]; //here kCollectionModelKey is a static string
[userDef synchronize];
}
//For Get CollectionModel
+ (CollectionModel *)getCollectionModel
{
NSUserDefaults *userDef = [NSUserDefaults standardUserDefaults];
CollectionModel *collectionModel = nil;
NSData *encodedData = [userDef objectForKey:kCollectionModelKey]; //Same static string use here kCollectionModelKey
if (encodedData != nil) {
collectionModel = [NSKeyedUnarchiver unarchiveObjectWithData:encodedData];
}
return collectionModel;
}

Save NSMutableArray of NSStrings to disk

I have a NSMutableaArray of NSString objects. So i'm using NSKeyedArchiever to save it to disk. So when i try to use
- (void)encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeObject:self.EventsList forKey:#"Events"];
}
i got an error
Event encodeWithCoder:]: unrecognized selector sent to instance 0x7fd06b542780
Here's my parts of code:
//-------------------Events.h--------------------------
#interface Event : NSObject
#property (strong,nonatomic) NSString *nameOfEvent;
#property (strong,nonatomic) NSString *dateOfEvent;
#property (strong,nonatomic) NSString *placeOfEvent;
#property int priorityOfEvent;
#end
//---------------Singleton.h ----------------
#interface GlobalSingleton : NSObject <NSCoding, NSCopying> {
NSMutableArray *EventsList;
}
#property (nonatomic,retain) NSMutableArray *EventsList;
+(GlobalSingleton *)sharedFavoritesSingleton;
#end
//----------------Singleton.m------------------------
....
#implementation GlobalSingleton
#synthesize EventsList;
....
....
- (void)encodeWithCoder:(NSCoder *)aCoder {
NSLog (#"%#",EventsList); // not nil
[aCoder encodeObject:self.EventsList forKey:#"Events"];
}
- (id)initWithCoder:(NSCoder *)aDecoder {
if ((self = [super init])) {
NSMutableArray *temp = [[NSMutableArray alloc] initWithArray:[aDecoder decodeObjectForKey:#"Events"]];
self.EventsList = temp;
}
return self;
}
- (id)copyWithZone:(NSZone *)zone {
GlobalSingleton *copy = [[GlobalSingleton allocWithZone:zone] init];
copy.EventsList = self.EventsList;
return copy;
}
#end
I get textdata from Web-server using ASIFormDataRequest in JSON format, and then i add this object to NSMutableArray, which is also a Singleton, so it looks like this:
NSDictionary *responseDict = [responseString JSONValue];
GlobalSingleton *Singleton = [GlobalSingleton sharedFavoritesSingleton];
for (NSDictionary *str in responseDict) {
Event *newEvent = [[Event alloc] init];
newEvent.nameOfEvent = [str objectForKey:#"EventName"];
newEvent.dateOfEvent = [str objectForKey:#"EventDate"];
newEvent.placeOfEvent = [str objectForKey:#"EventPlace"];
[Singleton.EventsList addObject:newEvent];
}
//------------------Save this data stored in NSMutableArray to disk-------------------------
[NSKeyedArchiver archiveRootObject:Singleton toFile:[self save_path]];
So, again, execution stops on this:
[aCoder encodeObject:self.EventsList forKey:#"Events"];
But when i try to code single NSString object everything goes with no errors.
eventList doesn't contain NSStrings, it contains Event objects.
Your Event class needs to implement encodeWithCoder: - as the exception message says, the Event class doesn't implement this method.
Also you should use a lowercase s for singleton as it is an instance, not a class, and you should probably not use singletons.

object is not saved in array

I have the following code that parses json into custom objects, parsing works fine i have a problem with saving the objects.
-(void)handleCities:(NSNotification *)notification
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"_getInitialData" object:nil];
if(![notification object])
{
NSLog(#"Something went wrong");
return;
}
// Convert data to a dictionary
NSMutableDictionary * data = [NSJSONSerialization JSONObjectWithData:(NSMutableData *) [notification object] options:NSJSONReadingMutableContainers error:nil];
// Loop over all the data
if([data objectForKey:#"data"] != (id)kCFBooleanFalse)
{
for(int i = 0; i < [[[data objectForKey:#"data"] objectForKey:#"cities"] count]; i++)
{
CityObject * object = [[CityObject alloc] init];
// Loop over all the properties
for(NSString * key in [[[data objectForKey:#"data"] objectForKey:#"cities" ] objectAtIndex:i])
{
NSString * _key = key;
if([object._remap objectForKey:key])
{
NSString * value = [object._remap objectForKey:_key];
NSLog(#"Notice [%#] Remapping \"%#\" to \"%#\"", self.class, _key, value);
_key = value;
}
// Save the value for easy access
NSString * value = [[[[data objectForKey:#"data"] objectForKey:#"cities" ] objectAtIndex:i] objectForKey:_key];
// Does the value have a value
if((id)value == [NSNull null])
{
value = #"";
}
// Set the value for key
[object setValue:value forKey:_key];
}
NSMutableDictionary * set = [[[data objectForKey:#"data"] objectForKey:#"cities"] objectAtIndex:i];
int count = (int)[[set objectForKey:#"categories"] count];
for(int b = 0; b < count; b++)
{
CategoryObject * category = [[CategoryObject alloc] init];
for(NSString * key in [[set objectForKey:#"categories"] objectAtIndex:b])
{
NSString * value = [[[set objectForKey:#"categories"] objectAtIndex:b] objectForKey:key];
if((id)value == [NSNull null])
{
value = #"";
}
[category setValue:value forKey:key];
}
NSLog(#"Category %#",category.class);
NSLog(#"Object : %#",object.class);
NSLog(#"Object Categories : %#",object.categories.class);
// i can print the category object fine here
[object.categories addObject:(CategoryObject *)category];
}
[self.cities addObject:object];
}
}
CityObject * city = [self.cities objectAtIndex:0];
CategoryObject * category = [city.categories objectAtIndex:0];
NSLog(#"Category Name : %#", category.name);
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"_getInitialData" object:nil];
[[NSNotificationCenter defaultCenter] postNotificationName:#"getInitialData" object:nil];
}
CityObject.h
#import <Foundation/Foundation.h>
#import "Object.h"
#interface CityObject : Object
#property (nonatomic, strong) NSString * name;
#property (nonatomic, strong) NSString * id;
#property (nonatomic, strong) NSString * state;
#property (nonatomic, strong) NSString * image;
#property (nonatomic, strong) NSString * term_order;
#property (nonatomic, strong) NSMutableArray * categories;
#property (nonatomic, strong) NSMutableDictionary * _remap;
#end
CityObject.m
#import "CityObject.h"
#implementation CityObject
-(id)init
{
if(self = [super init])
{
self._remap = [[NSMutableDictionary alloc] init];
self.categories = [[NSMutableArray alloc] init];
[self._remap setObject:#"state" forKey:#"new_city"];
}
return self;
}
#end
CategoryObject.h
#import <Foundation/Foundation.h>
#import "Object.h"
#interface CategoryObject : Object
#property (nonatomic, strong) NSString * name;
#property (nonatomic, strong) NSString * icon;
#property (nonatomic, strong) NSString * id;
#end
Before i add the CategoryObject to my array i can retrieve the values without a problem it is when i NSLog at the end i cannot get the values / objects out of the array's.
What am i doing wrong since it works great when i add the CityObjects but not when i "parse" the categories. I can read them fine before i add them to the object.categories
Error / Output
-[__NSDictionaryM name]: unrecognized selector sent to instance 0x7a482760
2015-03-24 09:21:05.649 10things[16968:337325] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSDictionaryM name]: unrecognized selector sent to instance 0x7a482760'
Problem solved, i did not have a strong pointer to the model, the Dictionary was magically being replaced to a NSMutableDictionary Once i had a strong handle everything worked properly. (thanks for the code feedback)

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;
}

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