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

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

Related

how can store custom objects in NSUserDefaults

I apologize for duplicate Question . I am new in ios . I want to store custom objects in userdefaults. I am using objective-c .
Thanks in advance
First you create custom class Like below.
CustomObject.h
#import <Foundation/Foundation.h>
#interface CustomObject : NSObject<NSCoding>
#property(strong,nonatomic)NSString *name;
#end
CustomObject.m
#import "CustomObject.h"
#implementation CustomObject
- (void)encodeWithCoder:(NSCoder *)encoder {
//Encode properties, other class variables, etc
[encoder encodeObject:self.name forKey:#"name"];
}
- (id)initWithCoder:(NSCoder *)decoder {
if((self = [super init])) {
//decode properties, other class vars
self.name = [decoder decodeObjectForKey:#"name"];
}
return self;
}
Then create CustomObject class object and store in NSUserDefaults
Stored your object like this
CustomObject *object =[CustomObject new];
object.name = #"test";
NSMutableArray *arr = [[NSMutableArray alloc]init];
[arr addObject:object];
NSData *encodedObject = [NSKeyedArchiver archivedDataWithRootObject:arr];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:encodedObject forKey:#"storeObject"];
[defaults synchronize];
get custom object from NSUserDefaults like this
NSData *storedEncodedObject = [defaults objectForKey:#"storeObject"];
NSArray *arrStoreObject = [NSKeyedUnarchiver unarchiveObjectWithData:storedEncodedObject];
for (int i=0; i<arrStoreObject.count; i++)
{
CustomObject *storedObject = [arrStoreObject objectAtIndex:i];
NSLog(#"%#",storedObject.name);
}
In Swift 3
// set a value for key
let encodedData = NSKeyedArchiver.archivedData(withRootObject: #YOUR OBJECT#)
UserDefaults.standard.set(encodedData, forKey: #YOUR KEY#)
// retrieving a value for a key
if let data = UserDefaults.standard.data(forKey: #YOUR KEY#),
let obj = NSKeyedUnarchiver.unarchiveObject(with: data) as? #YOUR OBJECT# {
} else {
print("There is an issue")
}

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

NSUserDefaults not saving complete Object

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.

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