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

如何将自定义struct保存到NSUserDefaults

 struct Paging { NSInteger currentPage; NSInteger totalResults; NSInteger resultsPerPage; }; typedef struct Paging Paging; NSUserDefaults *userInfo = [NSUserDefaults standardUserDefaults]; [userInfo setStruct:paging forKey:@"paging"]; [userInfo synchronize]; 

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

一种方法是把它变成NSData

 NSData* d = [NSData dataWithBytes: paging length: sizeof(paging)]; 

在这种情况下,你的结构非常简单,所以你可能需要添加一个类别到NSUserDefaults来保存和恢复它。 我会通过保存一个NSDictionary与四个NSNumbers实现。 多一点工作,但这意味着你的plist将是可读的。

在你的具体情况下,你可以放弃使用NSData因为成员只是int ,但是对于这个问题的未来读者,请阅读苹果公司关于编码和解码C数据types的文档。

编码和解码C数据types – 结构和位域 :

你不应该用一个NSData对象包装一个结构,并将其存档。 如果结构包含对象或指针字段,则数据对象不会正确存档 。 您还创build了编译器如何确定布局结构的依赖关系,编译器版本之间可能会发生变化,并可能取决于其他因素。 编译器并没有像在源代码中指定的那样组织一个结构 –例如, 结构中的字段之间可能有任意的内部和不可见的填充字节 ,并且这些字节的数量可以在没有通知的情况下改变,不同的平台。 另外,任何宽度为多个字节的字段在字节顺序问题上都不会得到正确的处理你会导致你自己的各种兼容性问题。

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

归档结构或位字段集合的最佳技术是独立存档字段,每个 字段select适当types的编码/解码方法 。 如果您愿意,键名可以由结构字段名构成,如"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]; } 

NSValue文档

我做了不太有利的决定,在我的iOS应用程序中使用结构。 现在我也面临这个问题,我无法轻易地将结构(包含大约30个variables)保存到NSUserDefaults中。

在尝试了许多在SO和其他网站上给出的解决scheme之后,对我来说效果并不好。 所以最后我决定创build一个简单的方法将结构转换成NSMutableDictionary。

 -(NSMutableDictionary *)structToDictionary:(StructPictures) dat { NSArray *values = [NSArray arrayWithObjects: [NSNumber numberWithFloat:dat.bgOpacity], [NSNumber numberWithInt:dat.bgType], // 1= general, [NSNumber numberWithFloat:dat.glowAmt], [NSNumber numberWithInt:dat.textureNum], [NSNumber numberWithInt:dat.patternNum], [NSNumber numberWithInt:dat.patternType], [NSNumber numberWithFloat:dat.patternHue], [NSNumber numberWithFloat:dat.textureSizer], [NSNumber numberWithInt:dat.stickerR], [NSNumber numberWithInt:dat.stickerG], [NSNumber numberWithInt:dat.stickerB] , nil]; NSArray *keys = [NSArray arrayWithObjects: @"bgOpacity", @"bgType", @"glowAmt", @"textureNum", @"patternNum", @"patternType", @"patternHue", @"textureSizer", @"stickerR", @"stickerG", @"stickerB", nil]; NSMutableDictionary *res = [[NSMutableDictionary alloc] initWithObjects:values forKeys:keys]; return res; } 

StructPictures是我的结构(自定义)的名称。 希望这给了另一种解决scheme来保存结构到NSUserDefaults。