4

我读过这个主题如何在 NSUserDefault 中保存我的数据类型?并从那里得到这个有用的代码部分:

MyObject *myObject = [[MyObject alloc] init];

NSData *myObjectData  = [NSData dataWithBytes:(void *)&myObject length:sizeof(myObject)];

[[NSUserDefaults standardUserDefaults] setObject:myObjectData forKey:@"kMyObjectData"];

用于保存数据并用于读取

 NSData *getData = [[NSData alloc] initWithData:[[NSUserDefaults standardUserDefaults] objectForKey:@"kMyObjectData"]];

MyObject *getObject;

[getData getBytes:&getObject];

ViewController当我将数据保存在一个中并在另一个中读取时,它的效果非常好。但是当我想在同一个班级中使用它时:

 - (IBAction)linkedInLog:(UIButton *)sender
{
    NSUserDefaults *myDefaults = [[NSUserDefaults standardUserDefaults] objectForKey:@"linkedinfo"];
    NSData *getData = [[NSData alloc] initWithData:myDefaults];
    LinkedContainer *getObject;
    [getData getBytes:&getObject];
    if (!myDefaults) {
        mLogInView = [[linkedInLoginView alloc]initWithNibName:@"linkedInLogInView" bundle:nil];
            [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(loginViewDidFinish:)
                                                     name:@"loginViewDidFinish"
                                                   object:mLogInView];
        [self.navigationController pushViewController:mLogInView animated:YES];
        if ((FBSession.activeSession.isOpen)&&(mLinkedInIsLogegOn)) {
            mMergeButton.hidden = NO;
        }
    }
    else{
        mLinkedInIsLogegOn= YES;
        mLinkedInInfo.mConsumer = getObject.mConsumer;
        mLinkedInInfo.mToken = getObject.mToken;
    }
}

出了点问题。在@selector:loginViewDidFinish 我将我的数据保存到NSUserDefaults

    -(void) loginViewDidFinish:(NSNotification*)notification
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    mLinkedInInfo.mConsumer = mLogInView.consumer;
    mLinkedInInfo.mToken = mLogInView.accessToken;
    NSData *myObjectData  = [NSData dataWithBytes:(void *)&mLinkedInInfo length:sizeof(mLinkedInInfo)];
    NSUserDefaults *lSave = [NSUserDefaults standardUserDefaults];
    [lSave setObject:myObjectData forKey:@"linkedinfo"];
    [lSave synchronize];
    if (mLinkedInInfo.mToken) {
        mLinkedInIsLogegOn = YES;
    }   
}

当涉及到其他部分时,程序总是崩溃。如果有人知道我做错了什么,请帮助我)

错误消息:线程 1:编译时 EXC_BAD_ACCESS(code=2,address 0x8)getObject.Consumer

4

2 回答 2

4

在绝大多数情况下,这不会是一种将对象序列化为 NSData 的有意义的方式:

MyObject *myObject = [[MyObject alloc] init];

NSData *myObjectData  = [NSData dataWithBytes:(void *)&myObject length:sizeof(myObject)];

[[NSUserDefaults standardUserDefaults] setObject:myObjectData forKey:@"kMyObjectData"];

执行此操作的规范方法是让 MyObject 采用 NSCoding 协议。根据您在此处发布的代码,NSCoding 的采用可能如下所示:

- (id)initWithCoder:(NSCoder *)coder
{
    if (self = [super init])
    {
        mConsumer = [coder decodeObjectForKey: @"consumer"];
        mToken = [coder decodeObjectForKey: @"token"];
    }
    return self;
}

- (void)encodeWithCoder:(NSCoder *)coder 
{
    [coder encodeObject:mConsumer forKey: @"consumer"];
    [coder encodeObject:mToken forKey:@"token"];
}

完成这项工作后,您可以像这样将 MyObject 与 NSData 相互转换:

NSData* data = [NSKeyedArchiver archivedDataWithRootObject: myObject];
MyObject* myObject = (MyObject*)[NSKeyedUnarchiver unarchiveObjectWithData: data];

您在此处的代码完全会破坏堆栈并崩溃(因为此行将[getData getBytes:&getObject];导致 NSData 将字节写入 getObject 的地址,该地址在堆栈上本地声明。因此堆栈粉碎。)从您的代码开始,a工作实现可能看起来像这样:

- (IBAction)linkedInLog:(UIButton *)sender
{
    NSData* dataFromDefaults = [[NSUserDefaults standardUserDefaults] objectForKey:@"linkedinfo"];
    LinkedContainer* getObject = (LinkedContainer*)[NSKeyedUnarchiver unarchiveObjectWithData: dataFromDefaults];
    if (!dataFromDefaults) {
        mLogInView = [[linkedInLoginView alloc]initWithNibName:@"linkedInLogInView" bundle:nil];
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(loginViewDidFinish:)
                                                     name:@"loginViewDidFinish"
                                                   object:mLogInView];
        [self.navigationController pushViewController:mLogInView animated:YES];
        if ((FBSession.activeSession.isOpen)&&(mLinkedInIsLogegOn)) {
            mMergeButton.hidden = NO;
        }
    }
    else{
        mLinkedInIsLogegOn= YES;
        mLinkedInInfo.mConsumer = getObject.mConsumer;
        mLinkedInInfo.mToken = getObject.mToken;
    }
}

-(void) loginViewDidFinish:(NSNotification*)notification
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    mLinkedInInfo.mConsumer = mLogInView.consumer;
    mLinkedInInfo.mToken = mLogInView.accessToken;
    NSData* objectData = [NSKeyedArchiver archivedDataWithRootObject: mLinkedInInfo];
    [[NSUserDefaults standardUserDefaults] setObject: objectData forKey: @"linkedinfo"];
    [[NSUserDefaults standardUserDefaults] synchronize];
    if (mLinkedInInfo.mToken) {
        mLinkedInIsLogegOn = YES;
    }
}
于 2013-08-29T12:24:19.543 回答
3

我同意 ipmcc 的回答,另一个可行的选择是向您的对象添加方法以将其转换为NSDictionary. 您也可以添加方法,-initWithDictionary并且应该使实例化非常容易。从字典中拉取NSUserDefaults使用,转换为字典保存。

这是具有通用数据的这两种方法的示例:

- (id)initWithDictionary:(NSDictionary *)dict
{
    self = [super init];

    // This check serves to make sure that a non-NSDictionary object
    // passed into the model class doesn't break the parsing.
    if(self && [dict isKindOfClass:[NSDictionary class]]) {
        NSObject *receivedFences = [dict objectForKey:@"fences"];
        NSMutableArray *parsedFences = [NSMutableArray array];
        if ([receivedFences isKindOfClass:[NSArray class]]) {
            for (NSDictionary *item in (NSArray *)receivedFences) {
                if ([item isKindOfClass:[NSDictionary class]]) {
                    [parsedFences addObject:[Fences modelObjectWithDictionary:item]];
                }
            }
        }
    }
    // More checks for specific objects here

    return self;

}

- (NSDictionary *)dictionaryRepresentation
{
    NSMutableDictionary *mutableDict = [NSMutableDictionary dictionary];
    NSMutableArray *tempArrayForFences = [NSMutableArray array];
    for (NSObject *subArrayObject in self.fences) {
        if([subArrayObject respondsToSelector:@selector(dictionaryRepresentation)]) {
            // This class is a model object
            [tempArrayForFences addObject:[subArrayObject performSelector:@selector(dictionaryRepresentation)]];
        } else {
            // Generic object
            [tempArrayForFences addObject:subArrayObject];
        }
    }

    [mutableDict setValue:[NSArray arrayWithArray:tempArrayForFences] forKey:@"fences"];

    return [NSDictionary dictionaryWithDictionary:mutableDict];
}

这基本上是由我使用的名为 JSON Accelerator 的程序生成的样板代码。它将读取 API 返回的 JSON 字符串并为您生成目标代码。不是一个真正的新概念,但可以很容易地为 API 创建类。这段代码非常适合创建要保存到NSUserDefaults. 希望这可以帮助。

于 2013-08-29T12:37:32.847 回答