I have a problem with saving from a custom class. I tried to save errors from some place in my code in NSUserDefaults but it doesn't work.
H file:
#import <Foundation/Foundation.h>
#interface Errors : NSObject<NSCoding>
#property (nonatomic,strong) NSString* type;
#property (nonatomic,strong) NSString* verNum;
#property (nonatomic,strong) NSString* title;
#property (nonatomic,strong) NSString* content;
#property (nonatomic,strong) NSString* source;
#property (nonatomic,strong) NSString* userId;
#property (nonatomic,strong) NSNumber* videoId;
#end
M file:
#import "Errors.h"
#implementation Errors
#synthesize verNum;
#synthesize type;
#synthesize title;
#synthesize content;
#synthesize source;
#synthesize userId;
#synthesize videoId;
- (void)encodeWithCoder:(NSCoder *)encoder{
[encoder encodeObject:self.verNum forKey:#"verNum"];
[encoder encodeObject:self.type forKey:#"type"];
[encoder encodeObject:self.title forKey:#"title"];
[encoder encodeObject:self.content forKey:#"content"];
[encoder encodeObject:self.source forKey:#"source"];
[encoder encodeObject:self.userId forKey:#"userId"];
[encoder encodeObject:self.videoId forKey:#"videoId"];
}
- (id)initWithCoder:(NSCoder *)decoder{
self = [super init];
if( self != nil ) {
self.verNum = [decoder decodeObjectForKey:#"verNum"];
self.type = [decoder decodeObjectForKey:#"type"];
self.title = [decoder decodeObjectForKey:#"title"];
self.content = [decoder decodeObjectForKey:#"content"];
self.source = [decoder decodeObjectForKey:#"source"];
self.userId = [decoder decodeObjectForKey:#"userId"];
self.videoId = [decoder decodeObjectForKey:#"videoId"];
}
return self;
}
#end
Saving:
errorsDitalis = [[Errors alloc]init];
errorsDitalis.verNum = (NSString *) [[request userInfo] objectForKey:#"verNum"];
errorsDitalis.type =(NSString *) [[request userInfo] objectForKey:#"type"];
errorsDitalis.title =(NSString *) [[request userInfo] objectForKey:#"title"];
errorsDitalis.content =(NSString *) [[request userInfo] objectForKey:#"content"];
errorsDitalis.source =(NSString *) [[request userInfo] objectForKey:#"source"];
errorsDitalis.userId =(NSString *) [[request userInfo] objectForKey:#"userId"];
errorsDitalis.videoId =(NSNumber *) [[request userInfo] objectForKey:#"videoId"];
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject:errorsDitalis forKey:#"ErrorList"];
[userDefaults synchronize];
Loading:
Errors * newError = [[Errors alloc]init];
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
newError = [userDefaults objectForKey:#"ErrorList"];
It just returns nil for newErrors. I tried to use this help but it didn't work. Does someone have an idea?
Try
[self setVerNum:[decoder decodeObjectForKey:#"verNum"]];
instead of
self.verNum = [decoder decodeObjectForKey:#"verNum"];
I believe you should use the setters when you call initWithCoder
i think i should do :
[[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:self.errorsDitalis] forKey:#"ErrorList"];
[[NSUserDefaults standardUserDefaults] synchronize];
and not:
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject:errorsDitalis forKey:#"ErrorList"];
[userDefaults synchronize];
and load with:
newError = (Errors *)[NSKeyedUnarchiver unarchiveObjectWithData:[[NSUserDefaults standardUserDefaults] objectForKey:#"ErrorList"]];
Related
I am saving the AccessToken that I got from one Social Networking website.when I save this then I come to know that We can't directly save the non property values in iOS SDK.
Then from tutorial I came to know that I should implement the NSCoding class. Then I did this.
NSData *myEncodedObject = [NSKeyedArchiver archivedDataWithRootObject:self.accessToken];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:myEncodedObject forKey:#"myEncodedObjectKey"];
[defaults synchronize];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *myEncodedObject = [defaults objectForKey:#"myEncodedObjectKey"];
LOAToken *obj = (LOAToken *)[NSKeyedUnarchiver unarchiveObjectWithData: myEncodedObject];
I implemented the NSCoding delegate but I don't know how to implement the delegate methods. Then when I run this code I get the error
`"-[LOAToken encodeWithCoder:]: unrecognized selector sent to instance 0xa2bb970"
I am unable to implement the NSCoding along with my code. Any Suggestions? Also Is there any other way to store the non-property values like AccessToken for further use.
Edit:
I am getting this access token of LinkedIn and want to store like this:
self.accessToken = [[LOAToken alloc] initWithHTTPResponseBody:responseBody];
// The accessToken Printed....Here I have the AccessToken Value.
NSLog(#"Access===%#",self.accessToken);
NSData *myEncodedObject = [NSKeyedArchiver archivedDataWithRootObject:self.accessToken];
NSLog(#"myEncodedObject===%#",myEncodedObject);
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:myEncodedObject forKey:#"myEncodedObjectKey"];
[defaults synchronize];
This was getting crashed since I have not used NSCoding implementation which I did in LOAToken class which you suggested.
I made one variable value in LAToken class and implemented these two methods.
-(void)encodeWithCoder:(NSCoder *)encoder
{
[encoder encodeObject:value forKey:#"Value"];
}
-(id)initWithCoder:(NSCoder *)decoder
{
self.value = [decoder decodeObjectForKey:#"Value"];
return self;
}
Then while retrieving I am using this.
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *myEncodedObject = [defaults objectForKey:#"myEncodedObjectKey"];
LOAToken *obj = (OAToken *)[NSKeyedUnarchiver unarchiveObjectWithData: myEncodedObject];
When I Printed the data both at the time of archiving and Unarchiving then the data printed is same.This may be due to two reasons.
The data which I have unarchived is right and the way of retrieving is wrong which you can suggest through my code above.
The data which I am saving at the time of Archiving is null.So the null is saved.
Is there any limitation in saving the Access Token.May be this can be a reason for null output.
The output which I got is this:
oauth_token "(null)" oauth_token_secret "(null)" oauth_verifier "(null)"
The text "oauth_token" "oauth_token_secret" "oauth_verifier" is coming from AccessToken but their values are null.
Edit 2: This is OAToken Class of LinkedIn where I am getting the Access Token.The same token I am passing in encoding method
OAToken.h
#import <Foundation/Foundation.h>
#interface OAToken : NSObject {
#protected
NSString *key;
NSString *secret;
NSString *session;
NSString *verifier;
NSNumber *duration;
NSMutableDictionary *attributes;
NSDate *created;
BOOL renewable;
BOOL forRenewal;
OAToken *value;
}
#property(retain, readwrite) NSString *key;
#property(retain, readwrite) NSString *secret;
#property(retain, readwrite) NSString *session;
#property(retain, readwrite) NSString *verifier;
#property(retain, readwrite) NSNumber *duration;
#property(retain, readwrite) NSMutableDictionary *attributes;
#property(readwrite, getter=isForRenewal) BOOL forRenewal;
#property (nonatomic,retain) OAToken *value;
- (id)initWithKey:(NSString *)aKey secret:(NSString *)aSecret;
- (id)initWithKey:(NSString *)aKey
secret:(NSString *)aSecret
session:(NSString *)aSession
verifier:(NSString *)aVerifier
duration:(NSNumber *)aDuration
attributes:(NSMutableDictionary *)theAttributes
created:(NSDate *)creation
renewable:(BOOL)renew;
- (id)initWithHTTPResponseBody:(NSString *)body;
- (id)initWithUserDefaultsUsingServiceProviderName:(NSString *)provider prefix:(NSString *)prefix;
- (int)storeInUserDefaultsWithServiceProviderName:(NSString *)provider prefix:(NSString *)prefix;
- (BOOL)isValid;
- (void)setAttribute:(NSString *)aKey value:(NSString *)aValue;
- (NSString *)attribute:(NSString *)aKey;
- (void)setAttributesWithString:(NSString *)aAttributes;
- (NSString *)attributeString;
- (BOOL)hasExpired;
- (BOOL)isRenewable;
- (void)setDurationWithString:(NSString *)aDuration;
- (void)setVerifierWithUrl:(NSURL *)aURL;
- (BOOL)hasAttributes;
- (NSMutableDictionary *)parameters;
- (BOOL)isEqualToToken:(OAToken *)aToken;
+ (void)removeFromUserDefaultsWithServiceProviderName:(const NSString *)provider prefix:(const NSString *)prefix;
#end
OAToken.m
#import "NSString+URLEncoding.h"
#import "OAToken.h"
#interface OAToken (Private)
+ (NSString *)settingsKey:(const NSString *)name provider:(const NSString *)provider prefix:(const NSString *)prefix;
+ (id)loadSetting:(const NSString *)name provider:(const NSString *)provider prefix:(const NSString *)prefix;
+ (void)saveSetting:(NSString *)name object:(id)object provider:(const NSString *)provider prefix:(const NSString *)prefix;
+ (NSNumber *)durationWithString:(NSString *)aDuration;
+ (NSMutableDictionary *)attributesWithString:(NSString *)theAttributes;
#end
#implementation OAToken
#synthesize key, secret, session, verifier, duration, attributes, forRenewal;
#synthesize value;
#pragma mark Encode
-(void)encodeWithCoder:(NSCoder *)encoder
{
// This prints the value....
NSLog(#"value===%#",self.value);
[encoder encodeObject:self.value forKey:#"Value"];
}
-(id)initWithCoder:(NSCoder *)decoder
{
OAToken *hell= [decoder decodeObjectForKey:#"Value"];
// This don't have the value.It is null.
NSLog(#"hell===%#",hell);
return self;
}
#pragma mark init
- (id)init {
return [self initWithKey:nil secret:nil];
}
- (id)initWithKey:(NSString *)aKey secret:(NSString *)aSecret {
return [self initWithKey:aKey secret:aSecret session:nil verifier:nil duration:nil
attributes:nil created:nil renewable:NO];
}
- (id)initWithKey:(NSString *)aKey
secret:(NSString *)aSecret
session:(NSString *)aSession
verifier:(NSString *)aVerifier
duration:(NSNumber *)aDuration
attributes:(NSMutableDictionary *)theAttributes
created:(NSDate *)creation
renewable:(BOOL)renew
{
[super init];
self.key = aKey;
self.secret = aSecret;
self.session = aSession;
self.verifier = aVerifier;
self.duration = aDuration;
self.attributes = theAttributes;
created = [creation retain];
renewable = renew;
forRenewal = NO;
return self;
}
- (void)setVerifierWithUrl:(NSURL *)aURL
{
NSString *query = [aURL query];
NSArray *pairs = [query componentsSeparatedByString:#"&"];
for (NSString *pair in pairs)
{
NSArray *elements = [pair componentsSeparatedByString:#"="];
if ([[elements objectAtIndex:0] isEqualToString:#"oauth_verifier"])
{
self.verifier = [elements objectAtIndex:1];
}
}
}
- (id)initWithHTTPResponseBody:(const NSString *)body
{
NSString *aKey = nil;
NSString *aSecret = nil;
NSString *aSession = nil;
NSString *aVerifier = nil;
NSNumber *aDuration = nil;
NSDate *creationDate = nil;
NSMutableDictionary *attrs = nil;
BOOL renew = NO;
NSArray *pairs = [body componentsSeparatedByString:#"&"];
for (NSString *pair in pairs)
{
NSArray *elements = [pair componentsSeparatedByString:#"="];
if ([[elements objectAtIndex:0] isEqualToString:#"oauth_token"])
{
aKey = [elements objectAtIndex:1];
}
else if ([[elements objectAtIndex:0] isEqualToString:#"oauth_token_secret"])
{
aSecret = [elements objectAtIndex:1];
}
else if ([[elements objectAtIndex:0] isEqualToString:#"oauth_verifier"])
{
aVerifier = [elements objectAtIndex:1];
}
else if ([[elements objectAtIndex:0] isEqualToString:#"oauth_session_handle"])
{
aSession = [elements objectAtIndex:1];
}
else if ([[elements objectAtIndex:0] isEqualToString:#"oauth_token_duration"])
{
aDuration = [[self class] durationWithString:[elements objectAtIndex:1]];
creationDate = [NSDate date];
}
else if ([[elements objectAtIndex:0] isEqualToString:#"oauth_token_attributes"])
{
attrs = [[self class] attributesWithString:[[elements objectAtIndex:1] decodedURLString]];
}
else if ([[elements objectAtIndex:0] isEqualToString:#"oauth_token_renewable"])
{
NSString *lowerCase = [[elements objectAtIndex:1] lowercaseString];
if ([lowerCase isEqualToString:#"true"] || [lowerCase isEqualToString:#"t"]) {
renew = YES;
}
}
}
value=[self initWithKey:aKey
secret:aSecret
session:aSession
verifier:aVerifier
duration:aDuration
attributes:attrs
created:creationDate
renewable:renew];
return [self initWithKey:aKey
secret:aSecret
session:aSession
verifier:aVerifier
duration:aDuration
attributes:attrs
created:creationDate
renewable:renew];
}
- (id)initWithUserDefaultsUsingServiceProviderName:(const NSString *)provider prefix:(const NSString *)prefix {
[super init];
self.key = [OAToken loadSetting:#"key" provider:provider prefix:prefix];
self.secret = [OAToken loadSetting:#"secret" provider:provider prefix:prefix];
self.session = [OAToken loadSetting:#"session" provider:provider prefix:prefix];
self.verifier = [OAToken loadSetting:#"verifier" provider:provider prefix:prefix];
self.duration = [OAToken loadSetting:#"duration" provider:provider prefix:prefix];
self.attributes = [OAToken loadSetting:#"attributes" provider:provider prefix:prefix];
created = [OAToken loadSetting:#"created" provider:provider prefix:prefix];
renewable = [[OAToken loadSetting:#"renewable" provider:provider prefix:prefix] boolValue];
if (![self isValid]) {
[self autorelease];
return nil;
}
return self;
}
#pragma mark dealloc
- (void)dealloc {
self.key = nil;
self.secret = nil;
self.duration = nil;
self.attributes = nil;
[super dealloc];
}
#pragma mark settings
- (BOOL)isValid {
return (key != nil && ![key isEqualToString:#""] && secret != nil && ![secret isEqualToString:#""]);
}
- (int)storeInUserDefaultsWithServiceProviderName:(const NSString *)provider prefix:(const NSString *)prefix {
[OAToken saveSetting:#"key" object:key provider:provider prefix:prefix];
[OAToken saveSetting:#"secret" object:secret provider:provider prefix:prefix];
[OAToken saveSetting:#"created" object:created provider:provider prefix:prefix];
[OAToken saveSetting:#"duration" object:duration provider:provider prefix:prefix];
[OAToken saveSetting:#"session" object:session provider:provider prefix:prefix];
[OAToken saveSetting:#"verifier" object:verifier provider:provider prefix:prefix];
[OAToken saveSetting:#"attributes" object:attributes provider:provider prefix:prefix];
[OAToken saveSetting:#"renewable" object:renewable ? #"t" : #"f" provider:provider prefix:prefix];
[[NSUserDefaults standardUserDefaults] synchronize];
return(0);
}
#pragma mark duration
- (void)setDurationWithString:(NSString *)aDuration {
self.duration = [[self class] durationWithString:aDuration];
}
- (BOOL)hasExpired
{
return created && [created timeIntervalSinceNow] > [duration intValue];
}
- (BOOL)isRenewable
{
return session && renewable && created && [created timeIntervalSinceNow] < (2 * [duration intValue]);
}
#pragma mark attributes
- (void)setAttribute:(const NSString *)aKey value:(const NSString *)aAttribute {
if (!attributes) {
attributes = [[NSMutableDictionary alloc] init];
}
[attributes setObject: aAttribute forKey: aKey];
}
- (void)setAttributes:(NSMutableDictionary *)theAttributes {
[attributes release];
if (theAttributes) {
attributes = [[NSMutableDictionary alloc] initWithDictionary:theAttributes];
}else {
attributes = nil;
}
}
- (BOOL)hasAttributes {
return (attributes && [attributes count] > 0);
}
- (NSString *)attributeString {
if (![self hasAttributes]) {
return #"";
}
NSMutableArray *chunks = [[NSMutableArray alloc] init];
for(NSString *aKey in self->attributes) {
[chunks addObject:[NSString stringWithFormat:#"%#:%#", aKey, [attributes objectForKey:aKey]]];
}
NSString *attrs = [chunks componentsJoinedByString:#";"];
[chunks release];
return attrs;
}
- (NSString *)attribute:(NSString *)aKey
{
return [attributes objectForKey:aKey];
}
- (void)setAttributesWithString:(NSString *)theAttributes
{
self.attributes = [[self class] attributesWithString:theAttributes];
}
- (NSMutableDictionary *)parameters
{
NSMutableDictionary *params = [[[NSMutableDictionary alloc] init] autorelease];
if (key)
{
[params setObject:key forKey:#"oauth_token"];
if ([self isForRenewal])
{
[params setObject:session forKey:#"oauth_session_handle"];
}
}
else
{
if (duration)
{
[params setObject:[duration stringValue] forKey: #"oauth_token_duration"];
}
if ([attributes count])
{
[params setObject:[self attributeString] forKey:#"oauth_token_attributes"];
}
}
if (verifier)
{
[params setObject:verifier forKey:#"oauth_verifier"];
}
return params;
}
#pragma mark comparisions
- (BOOL)isEqual:(id)object {
if([object isKindOfClass:[self class]]) {
return [self isEqualToToken:(OAToken *)object];
}
return NO;
}
- (BOOL)isEqualToToken:(OAToken *)aToken {
/* Since ScalableOAuth determines that the token may be
renewed using the same key and secret, we must also
check the creation date */
if ([self.key isEqualToString:aToken.key] &&
[self.secret isEqualToString:aToken.secret]) {
/* May be nil */
if (created == aToken->created || [created isEqualToDate:aToken->created]) {
return YES;
}
}
return NO;
}
#pragma mark class_functions
+ (NSString *)settingsKey:(NSString *)name provider:(NSString *)provider prefix:(NSString *)prefix {
return [NSString stringWithFormat:#"OAUTH_%#_%#_%#", provider, prefix, [name uppercaseString]];
}
+ (id)loadSetting:(NSString *)name provider:(NSString *)provider prefix:(NSString *)prefix {
return [[NSUserDefaults standardUserDefaults] objectForKey:[self settingsKey:name
provider:provider
prefix:prefix]];
}
+ (void)saveSetting:(NSString *)name object:(id)object provider:(NSString *)provider prefix:(NSString *)prefix {
[[NSUserDefaults standardUserDefaults] setObject:object forKey:[self settingsKey:name
provider:provider
prefix:prefix]];
}
+ (void)removeFromUserDefaultsWithServiceProviderName:(NSString *)provider prefix:(NSString *)prefix {
NSArray *keys = [NSArray arrayWithObjects:#"key", #"secret", #"created", #"duration", #"session", #"verifier", #"attributes", #"renewable", nil];
for(NSString *name in keys) {
[[NSUserDefaults standardUserDefaults] removeObjectForKey:[OAToken settingsKey:name provider:provider prefix:prefix]];
}
}
+ (NSNumber *)durationWithString:(NSString *)aDuration {
NSUInteger length = [aDuration length];
unichar c = toupper([aDuration characterAtIndex:length - 1]);
int mult;
if (c >= '0' && c <= '9') {
return [NSNumber numberWithInt:[aDuration intValue]];
}
if (c == 'S') {
mult = 1;
} else if (c == 'H') {
mult = 60 * 60;
} else if (c == 'D') {
mult = 60 * 60 * 24;
} else if (c == 'W') {
mult = 60 * 60 * 24 * 7;
} else if (c == 'M') {
mult = 60 * 60 * 24 * 30;
} else if (c == 'Y') {
mult = 60 * 60 * 365;
} else {
mult = 1;
}
return [NSNumber numberWithInt: mult * [[aDuration substringToIndex:length - 1] intValue]];
}
+ (NSMutableDictionary *)attributesWithString:(NSString *)theAttributes {
NSArray *attrs = [theAttributes componentsSeparatedByString:#";"];
NSMutableDictionary *dct = [[NSMutableDictionary alloc] init];
for (NSString *pair in attrs) {
NSArray *elements = [pair componentsSeparatedByString:#":"];
[dct setObject:[elements objectAtIndex:1] forKey:[elements objectAtIndex:0]];
}
return [dct autorelease];
}
#pragma mark description
- (NSString *)description {
return [NSString stringWithFormat:#"oauth_token \"%#\" oauth_token_secret \"%#\" oauth_verifier \"%#\"", key, secret, verifier];
}
#end
You don't need any delegate methods. Instead, LOAToken should implement the initWithCoder: and encodeWithCoder: methods to actually save and restore the information that it contains. This is the meaning of implementing the NSCoding protocol.
You may want to have a read of the archiving docs here.
Once you have initially created your token from a web response or similar you should be using storeInUserDefaultsWithServiceProviderName: to store it into user defaults. Then, when you want to use it again call initWithUserDefaultsUsingServiceProviderName:. You don't need to do any encoding and decoding yourself.
To unarchive data
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *data = [defaults objectForKey:#"key"];
NSArray *arr = [NSKeyedUnarchiver unarchiveObjectWithData:data];
to archive data
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:array];
[defaults setValue:data forKey:#"key"];
[defaults synchronize];
Iam trying to save NSMutableDictionary to NSUserDefaults with this code:
NSUserDefaults *def = [NSUserDefaults standardUserDefaults];
NSMutableDictionary *repositoryData = [[NSMutableDictionary alloc] init];
[repositoryData setObject:personData forKey:#"persondata"];
[def setObject:repositoryData forKey:#"kUserRepository"];
[def synchronize];
[repositoryData removeAllObjects];
[repositoryData release];
But i am getting this msg:
[NSUserDefaults setObject:forKey:]: Attempt to insert non-property value '{
persondata = "<Person: 0x1ed57e70>";
}' of class '__NSDictionaryM'. Note that dictionaries and arrays in property lists must also contain only property values.
and also the Person Class have NSCoding:
Person.h
#interface Person : NSObject <NSCoding> {
NSString *name;
NSString *email;
NSString *phoneNumber;
NSString *gender;
int age;
}
#property (nonatomic, retain) NSString *name;
#property (nonatomic, retain) NSString *email;
#property (nonatomic, retain) NSString *phoneNumber;
#property (nonatomic, retain) NSString *gender;
#property (assign) int age;
#end
Person.m
#implementation Person
#synthesize name,email,phoneNumber,age,gender;
#pragma mark
#pragma mark NSCoder
- (void)encodeWithCoder:(NSCoder *)encoder{
[encoder encodeObject:self.name forKey:#"username"];
[encoder encodeObject:self.email forKey:#"useremail"];
[encoder encodeObject:self.phoneNumber forKey:#"userphonenumber"];
[encoder encodeObject:self.gender forKey:#"usergender"];
[encoder encodeInt:self.age forKey:#"userage"];
}
- (id)initWithCoder:(NSCoder *)decoder {
if(self = [super init]){
self.name = [decoder decodeObjectForKey:#"username"];
self.email = [decoder decodeObjectForKey:#"useremail"];
self.phoneNumber = [decoder decodeObjectForKey:#"userphonenumber"];
self.gender = [decoder decodeObjectForKey:#"usergender"];
self.age = [decoder decodeIntForKey:#"userage"];
}
return self;
}
#end
Any idea why it happen?
There are very specific restrictions as to what type of data can be synced to NSUserDefaults within an NSDictionary. These include NSString, NSNumber, NSData, NSArray and NSDictionary. Use your NSCoder methods to serialize to NSData (using NSKeyedArchiver) before storing in the NSUserDefaults.
Also, take a look at this
I would like to persist an object of a class (not just NSStringĀ“s). For instance, I have this class:
** News.h:**
#import <Foundation/Foundation.h>
#interface News : NSObject
#property (nonatomic, retain) NSString * atrib1;
#property (nonatomic, retain) NSString * atrib2;
#end
** News.m:**
#import "News.h"
#implementation News
#synthesize atrib1;
#synthesize atrib2;
#end
Should I have to use a plist to storage it? How should I do it?
Using NSCoding:
In News.m, I have added:
- (void) encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:atrib1 forKey:#"key1"];
[encoder encodeObject:atrib2 forKey:#"key2"];
}
- (id)initWithCoder:(NSCoder *)decoder {
self = [super init];
atrib1 = [[decoder decodeObjectForKey:#"key1"] retain];
atrib2 = [[decoder decodeObjectForKey:#"key2"] retain];
return self;
}
-(void)dealloc{
[super dealloc];
[atrib1 release];
[atrib2 release];
}
In News.h:
#interface News : NSObject<NSCoding>{
NSCoder *coder;
}
#property (nonatomic, retain) NSString * atrib1;
#property (nonatomic, retain) NSString * atrib2;
#end
To read update and persist a new object in the plist:
- (IBAction)addANewNews:(id)sender {
//Plist File
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *plistPath = [[paths objectAtIndex:0] stringByAppendingPathComponent:#"myplist.plist"];
//Reading current news
NSData *oldNews = [NSData dataWithContentsOfFile:plistPath];
NSMutableArray *news = (NSMutableArray *)[NSKeyedUnarchiver unarchiveObjectWithData:oldNews];
if (news == nil)
news = [[NSMutableArray alloc] init];
//Adding a new news
[news addObject:aNewNews];
NSError *error;
NSData* newData = [NSKeyedArchiver archivedDataWithRootObject:news];
//persisting the updated news
BOOL success =[newData writeToFile:plistPath options:NSDataWritingAtomic error:&error];
if (!success) {
NSLog(#"Could not write file.");
}else{
NSLog(#"Success");
}
}
My issue is then I retrieve my NSArray of Store objects, all my NSString properties are causing BadAccess errors. The int and double properties work fine!
store.h
#interface Store : NSObject<NSCoding> {
NSString *Name;
NSString *Address;
NSString *Phone;
double GeoLong;
double GeoLat;
int ID;
}
#property (nonatomic, retain) NSString *Name;
#property (nonatomic, retain) NSString *Address;
#property (nonatomic, retain) NSString *Phone;
#property (nonatomic) double GeoLat;
#property (nonatomic) double GeoLong;
#property (nonatomic) int ID;
#end
store.m
#implementation Store
#synthesize Name;
#synthesize ID;
#synthesize Address;
#synthesize Phone;
#synthesize GeoLat;
#synthesize GeoLong;
/** Implentation of the NSCoding protocol. */
-(void)encodeWithCoder:(NSCoder *)encoder
{
[encoder encodeInt:ID forKey:#"ID"];
[encoder encodeDouble:GeoLat forKey:#"GeoLat"];
[encoder encodeDouble:GeoLong forKey:#"GeoLong"];
NSLog(#"Name in encode: %#", Name); //WORKS!
[encoder encodeObject:Name forKey:#"Name"];
[encoder encodeObject:Phone forKey:#"Phone"];
[encoder encodeObject:Address forKey:#"Address"];
}
-(id)initWithCoder:(NSCoder *)decoder
{
// Init first.
if(self = [self init]){
ID = [decoder decodeIntForKey:#"ID"];
GeoLat = [decoder decodeDoubleForKey:#"GeoLat"];
GeoLong = [decoder decodeDoubleForKey:#"GeoLong"];
Name = [decoder decodeObjectForKey:#"Name"];
NSLog(#"Name in decode: %#", Name); //WORKS! logs the name
Address = [decoder decodeObjectForKey:#"Address"];
Phone = [decoder decodeObjectForKey:#"Phone"];
}
return self;
}
- (void)dealloc
{
[Name release];
[ID release];
[Address release];
[Phone release];
[super dealloc];
}
#end
Here is my code for storing and retriving the array.
//streams contains the data i will populate my array with.
for (ndx = 0; ndx < streams.count; ndx++) {
NSDictionary *stream = (NSDictionary *)[streams objectAtIndex:ndx];
Store *item = [[Store alloc] init] ;
item.Name = [stream valueForKey:#"Name"];
item.Address = [stream valueForKey:#"Address"];
item.Phone = [stream valueForKey:#"Phone"];
item.GeoLat = [[stream valueForKey:#"GeoLat"] doubleValue];
item.GeoLong = [[stream valueForKey:#"GeoLong"] doubleValue];
item.ID = [[stream valueForKey:#"ID"] intValue];
[listToReturn addObject:item];
}
}
//test to check if it works
for(int i = 0; i < [listToReturn count]; i++){
Store *item = (Store *)[listToReturn objectAtIndex:i];
NSLog(#"Name: %#", item.Name); //works
}
//save
[[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:listToReturn] forKey:#"stores"];
// retrieve
NSMutableArray *stores = [NSMutableArray new];
NSUserDefaults *currentDefaults = [NSUserDefaults standardUserDefaults];
NSData *dataRepresentingSavedArray = [currentDefaults objectForKey:#"stores"];
if (dataRepresentingSavedArray != nil)
{
NSArray *oldSavedArray = [NSKeyedUnarchiver unarchiveObjectWithData:dataRepresentingSavedArray];
if (oldSavedArray != nil)
stores = [[NSMutableArray alloc] initWithArray:oldSavedArray];
else
stores = [[NSMutableArray alloc] init];
}
if ([stores count] > 0) {
NSMutableArray * annotations = [[NSMutableArray alloc] init];
for(int i = 0;i< [stores count]; i++){
Store *store = [stores objectAtIndex: i];
CLLocationCoordinate2D location;
if(store.GeoLat != 0 && store.GeoLong != 0){
location.latitude = store.GeoLat;
location.longitude = store.GeoLong; //works
NSLog(#"Adding store: %#", store.Name); //DONT WORK!! <-- MAIN PROBLEM
}
}
}
Feels like I tried everything but can't figure out how it works in the decode but not when in loop the array after I put it into a array.
Anyone have any ideas?
You're not retaining the properties in initWithCoder.
Name = [decoder decodeObjectForKey:#"Name"];
is not using the setter of the (retaining) property you've defined. You're just setting the ivar. That means you don't acquire ownership and it can be deallocated.
Here are two ways you can retain the properties in your case:
self.Name = [decoder decodeObjectForKey:#"Name"];
Name = [[decoder decodeObjectForKey:#"Name"] retain];
I have spent hours trying to get my project working and I just can't get it working.
Basically, I'm trying to use NSUserDefaults to save a custom object when the user hits a save button and load all the data up when the app loads. If there is no previous NSUserDefault saved, I want to set some defaults. In the end, I am getting EXC_BAD_ACCESS when trying to load a previously-saved NSUserDefault. It works fine the first load, when setting the starting data. And the thing is, when I try to enable NSZombieEnabled and the other env vars for it, it somehow loads fine without the EXC_BAD_ACCESS. So here's what I'm working with:
[App Delegate.h]
#import <UIKit/UIKit.h>
#import "Note.h"
#interface ToDoWallAppDelegate : NSObject <UIApplicationDelegate> {
...
Note *note;
}
...
#property (retain) Note *note;
#end
[App Delegate.m]
- (void)applicationDidFinishLaunching:(UIApplication *)application {
...
note = [[Note alloc] init];
NSUserDefaults *stdDefaults = [NSUserDefaults standardUserDefaults];
NSData *noteData = [stdDefaults objectForKey:#"Note"];
if (noteData) {
self.note = (Note *)[NSKeyedUnarchiver unarchiveObjectWithData:noteData];
} else {
note.background = [UIImage imageNamed:#"Cork.jpg"];
note.picture = [UIImage imageNamed:#"Cork.jpg"];
note.font = [UIFont fontWithName:#"Helvetica" size:18.0f];
note.fontColor = [UIColor blackColor];
note.fontNameIndex = 9;
note.fontSizeIndex = 6;
note.fontColorIndex = 0;
note.backgroundIndexPath = [NSIndexPath indexPathForRow:0 inSection:0];
note.pictureIndexPath = [NSIndexPath indexPathForRow:0 inSection:0];
note.text = #"Type note here...";
}
...
}
- (void)dealloc {
...
[note release];
[super dealloc];
}
[View Controller]
- (void)saveNote {
...
NSUserDefaults *stdDefaults = [NSUserDefaults standardUserDefaults];
if (stdDefaults) {
NSData *noteData = [NSKeyedArchiver archivedDataWithRootObject:UIAppDelegate.note];
[stdDefaults setObject:noteData forKey:#"Note"];
[stdDefaults synchronize];
}
}
[Note.h]
#import <Foundation/Foundation.h>
#interface Note : NSObject <NSCoding> {
UIImage *background, *picture;
UIFont *font;
UIColor *fontColor;
int fontNameIndex, fontSizeIndex, fontColorIndex;
NSIndexPath *backgroundIndexPath, *pictureIndexPath;
BOOL customBackground;
NSString *text;
}
#property (retain) UIImage *background, *picture;
#property (retain) UIFont *font;
#property (retain) UIColor *fontColor;
#property int fontNameIndex, fontSizeIndex, fontColorIndex;
#property (retain) NSIndexPath *backgroundIndexPath, *pictureIndexPath;
#property BOOL customBackground;
#property (retain) NSString *text;
- (Note *)init;
#end
[Note.m]
#import "Note.h"
#implementation Note
#synthesize background, picture, font, fontColor, fontNameIndex, fontSizeIndex, fontColorIndex, customBackground, backgroundIndexPath, pictureIndexPath, text;
- (Note *)init {
if (self = [super init]) {
background = [[UIImage alloc] init];
picture = [[UIImage alloc] init];
font = [[UIFont alloc] init];
fontColor = [[UIColor alloc] init];
backgroundIndexPath = [[NSIndexPath alloc] init];
pictureIndexPath = [[NSIndexPath alloc] init];
text = [[NSString alloc] init];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)encoder {
NSData *dataBackground = UIImagePNGRepresentation(background);
NSData *dataPicture = UIImagePNGRepresentation(picture);
[encoder encodeObject:dataBackground forKey:#"dataBackground"];
[encoder encodeObject:dataPicture forKey:#"dataPicture"];
[encoder encodeObject:font forKey:#"font"];
[encoder encodeObject:fontColor forKey:#"fontColor"];
[encoder encodeInt:fontSizeIndex forKey:#"fontSizeIndex"];
[encoder encodeInt:fontColorIndex forKey:#"fontColorIndex"];
[encoder encodeBool:customBackground forKey:#"customBackground"];
[encoder encodeObject:backgroundIndexPath forKey:#"backgroundIndexPath"];
[encoder encodeObject:pictureIndexPath forKey:#"pictureIndexPath"];
[encoder encodeObject:text forKey:#"text"];
}
- (Note *)initWithCoder:(NSCoder *)decoder {
if (self = [super init]) {
NSData *dataBackground = [decoder decodeObjectForKey:#"dataBackground"];
NSData *dataPicture = [decoder decodeObjectForKey:#"dataPicture"];
background = [[UIImage imageWithData:dataBackground] retain];
picture = [[UIImage imageWithData:dataPicture] retain];
font = [[decoder decodeObjectForKey:#"font"] retain];
fontColor = [[decoder decodeObjectForKey:#"fontColor"] retain];
fontNameIndex = [decoder decodeIntForKey:#"fontNameIndex"];
fontColorIndex = [decoder decodeIntForKey:#"fontColorIndex"];
customBackground = [decoder decodeBoolForKey:#"customBackground"];
backgroundIndexPath = [[decoder decodeObjectForKey:#"backgroundIndexPath"] retain];
text = [[decoder decodeObjectForKey:#"text"] retain];
}
return self;
}
- (void)dealloc {
[super dealloc];
[background release];
[picture release];
[font release];
[fontColor release];
[backgroundIndexPath release];
[pictureIndexPath release];
[text release];
}
#end
I really need some help I appreciate it.
Edit:
Btw, there are also lines from other files that edit the App Delegate's Note object, such as:
#define UIAppDelegate ((ToDoWallAppDelegate *)[UIApplication sharedApplication].delegate)
...
UIAppDelegate.note.backgroundIndexPath = indexPath;
Edit:
This is what debugger wrote:
#0 0x90be9ed7 in objc_msgSend
#1 0x03b05210 in ??
#2 0x000023ce in -[ToDoWallAppDelegate setNote:] at ToDoWallAppDelegate.m:14
#3 0x00002216 in -[ToDoWallAppDelegate applicationDidFinishLaunching:] at ToDoWallAppDelegate.m:35
Which are:
note.text = #"Type note here...";
//and
#synthesize window, note;
I'm not sure if this is what's causing your problem, but I believe that [super dealloc] should be the LAST line of your dealloc method, not the first.
Have a look at documentation how to setup defaults
Using NSUserDefaults
If you need more info have a look in Hillega's book "Cocoa programming for Mac OS X" bignerdranch.com/books, it's explained there.
You should consider changing the headline to "How to use NSUserDefaults" ...
Example how to setup default value, in your class in initialize put something like:
+ (void)initialize{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSDictionary *appDefaults = [NSDictionary
dictionaryWithObject:#"YES" forKey:#"DeleteBackup"];
[defaults registerDefaults:appDefaults];
}
You could post where exactly are you getting the error instead of posting the whole code. Run it through debugger and see where it stops.