Domanda

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.

  1. The data which I have unarchived is right and the way of retrieving is wrong which you can suggest through my code above.

  2. 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
È stato utile?

Soluzione

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.

Altri suggerimenti

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];
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top