如何使用NSUserDefaults在iOS中保存非属性值?

时间:2013-08-06 13:33:23

标签: iphone ios ipad cocoa-touch nscoding

我正在保存我从一个社交网站上获得的AccessToken。当我保存这个时,我才知道我们无法直接在iOS SDK中保存非属性值。

然后从教程我开始知道我应该实现NSCoding类。然后我就这样做了。

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

我实施了NSCoding委托,但我不知道如何实施delegate methods。然后,当我运行此代码时,我收到错误

`"-[LOAToken encodeWithCoder:]: unrecognized selector sent to instance 0xa2bb970"

我无法将NSCoding与我的代码一起实现。有什么建议?还有其他方法来存储非属性值,如AccessToken以供进一步使用。

修改

我正在获取LinkedIn的这个访问令牌,并希望像这样存储:

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

由于我没有使用我在NSCoding课程中所做的LOAToken实现,因此崩溃了。

我在LAToken类中创建了一个变量值并实现了这两种方法。

-(void)encodeWithCoder:(NSCoder *)encoder
{
    [encoder encodeObject:value forKey:@"Value"];
}

-(id)initWithCoder:(NSCoder *)decoder
{
    self.value = [decoder decodeObjectForKey:@"Value"];
    return self;
}

然后在检索时我正在使用它。

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    NSData *myEncodedObject = [defaults objectForKey:@"myEncodedObjectKey"];
    LOAToken *obj = (OAToken *)[NSKeyedUnarchiver unarchiveObjectWithData: myEncodedObject];

当我在存档和取消归档时打印数据时,打印的数据是相同的。这可能是由于两个原因。

  1. 我取消归档的数据是正确的,检索方式错误,您可以通过上面的代码建议。

  2. 我在存档时保存的数据为空。这样就保存了空。

  3. 保存访问令牌是否有任何限制。可能这是空输出的原因。

    我得到的输出是:

    oauth_token "(null)" oauth_token_secret "(null)" oauth_verifier "(null)"
    

    文字"oauth_token" "oauth_token_secret" "oauth_verifier"来自AccessToken,但其值为空。

    编辑2:这是我获得访问令牌的LinkedIn的OAToken类。我在编码方法中传递的相同标记

    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
    

2 个答案:

答案 0 :(得分:4)

您不需要任何委托方法。相反,LOAToken应实现initWithCoder:encodeWithCoder:方法,以实际保存和恢复其包含的信息。这是实现NSCoding协议的意义。

您可能希望阅读归档文档here


一旦您最初从Web响应或类似响应中创建了令牌,您应该使用storeInUserDefaultsWithServiceProviderName:将其存储到用户默认值中。然后,当您想再次使用它时,请致电initWithUserDefaultsUsingServiceProviderName:。您不需要自己进行任何编码和解码。

答案 1 :(得分:0)

取消归档数据

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *data = [defaults objectForKey:@"key"];
NSArray *arr = [NSKeyedUnarchiver unarchiveObjectWithData:data];

归档数据

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];       
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:array];
[defaults setValue:data forKey:@"key"];
[defaults synchronize];