如何在Objective-c中将结构保存到NSUserDefaults?

MUH*_*nc. 4 c struct objective-c nsuserdefaults ios

如何保存自定义structNSUserDefaults

struct Paging {
    NSInteger currentPage;
    NSInteger totalResults;
    NSInteger resultsPerPage;
};

typedef struct Paging Paging;

NSUserDefaults *userInfo = [NSUserDefaults standardUserDefaults];
[userInfo setStruct:paging forKey:@"paging"];
[userInfo synchronize];
Run Code Online (Sandbox Code Playgroud)

上面的代码产生一个运行时警告:
*** -[NSUserDefaults setObject:forKey:]: Attempt to insert non-property value...

cho*_*own 5

在您的具体情况下,您可以使用,NSData因为成员只是ints,但对于此问题的未来读者,请在执行此操作之前阅读有关编码和解码C数据类型的Apple文档!

编码和解码C数据类型 - 结构和位域:

您应该换行与结构NSData对象和归档.如果结构包含对象或指针字段,则数据对象不会正确归档它们.您还会依赖于编译器如何决定布局结构,这可能会在编译器版本之间发生变化,并且可能取决于其他因素.编译器不限于组织结构,就像在源代码中指定结构一样 -例如,结构中的字段之间可能存在任意内部和不可见的填充字节,并且这些字节的数量可以更改,恕不另行通知不同的平台.此外,任何宽度为多个字节的字段都不会在字节顺序问题上得到正确处理.你会给自己带来各种各样的兼容性问题.

该文档确实说明了如何正确地做到这一点(但不幸的是没有给出一个例子 - 但是当我想出一个时,我会用这个例子更新这个答案):

归档结构或位字段集合的最佳技术是独立归档字段,每个字段选择 适当类型的编码/解码方法.如果您愿意,可以从结构字段名称组成键名,例如 "theStruct.order","theStruct.flags"等等.这会对源代码中的字段名称产生轻微的依赖性,随着时间的推移可能会重命名,但如果要保持兼容性,则归档密钥不会更改.


一种非常类似于NSData包装但使用的方法NSValue(这也是不鼓励的,但也适用于基本结构):

struct Paging {
    NSInteger currentPage;
    NSInteger totalResults;
    NSInteger resultsPerPage;
};

typedef struct Paging Paging;

- (void)someMeth {
    // Here `paging_struct` is a struct of type `Paging`:
    NSValue *pagingStructValue;
    // On its own line just for readability
    pagingStructValue = [NSValue valueWithBytes:&paging_struct
                                       objCType:@encode(Paging)];

    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    [userDefaults setObject:pagingStructValue
                     forKey:@"paging"];
    [userDefaults synchronize];
}
Run Code Online (Sandbox Code Playgroud)

NSValue 文档

  • 不幸的是,这种方法在iOS 6+上对我不起作用.我得到:尝试插入'NSConcreteValue'类的非属性值... 请注意,属性列表中的字典和数组也必须仅包含属性值. (3认同)