ios - 保存自己的数据类型时使用 NSUserDefaults

标签 ios objective-c nsuserdefaults

我读过这个话题How to save My Data Type in 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 中并在另一个中读取时,它的效果非常好。 但是当我想在同一个类(class)使用它时:

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

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

错误信息:Thread 1 : EXC_BAD_ACCESS(code=2,address 0x8) when compiling getObject.Consumer

最佳答案

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

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

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

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

执行此操作的规范方法是让 MyObject 采用 NSCoding 协议(protocol)。根据您在此处发布的代码,采用 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,它在堆栈上本地声明。因此堆栈粉碎。)从您的代码开始,一个有效的实现可能看起来像这样:

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

关于ios - 保存自己的数据类型时使用 NSUserDefaults,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18509921/

相关文章:

ios - 代号一 - Validator 类的 addSubmitButtons 方法更改按钮样式

objective-c - 确定一个 NSMenu 是否被打开

ios - 如何将枚举保存到用户默认值?

iphone - 如何用cocos2d-iphone旋转 Sprite 180度?

ios - 当应用程序在后台使用 Sinch iOS SDK 时无法处理来电推送通知

ios - swift ios 中的 URL 编码问题

objective-c - 需要一个 float 以标准形式 Obj C 显示

c++ - 在 Objective-C 中使用 fopen()

c# - 如何在 NSUserDefaults.StandardUserDefaults 中保存日期时间(日期)?

objective-c - 如何在 NSUserDefaults 中存储带有 block 变量的自定义对象