在用户默认值中使用UIImage保存NSDictionary

时间:2013-11-23 20:42:58

标签: ios

正如标题所说,我试图在用户默认情况下保存一个带有一些UIImages的NSDictionary:

UIImage* img = PhotoView.image;
NSMutableDictionary *UserInfoDictionary = [[NSMutableDictionary  alloc] init];
[UserInfoDictionary setObject:img forKey:@"ProfileImage"];
[UserInfoDictionary setObject:ProfileUsername.text forKey:@"Username"];
[[NSUserDefaults standardUserDefaults] setObject:UserInfoDictionary forKey:@"ProfileAndFolderInformation"];

字典中最多可添加30张图片,但现在应用程序因错误而崩溃:

Attempt to set a non-property-list object {
ProfileImage = "<UIImage: 0x16dc4280>";
} as an NSUserDefaults value for key ProfileAndFolderInformation
2013-11-23 21:39:00.261 Cleverly[363:60b] *** Terminating app due to uncaught exception    'NSInvalidArgumentException', reason: '*** -[NSUserDefaults setObject:forKey:]: attempt to insert non-property list object {
ProfileImage = "<UIImage: 0x16dc4280>";
} for key ProfileAndFolderInformation'
*** First throw call stack:
(0x30b59e83 0x3aeba6c7 0x30b59dc5 0x3148aa91 0xbaad9 0x33312da3 0x33312d3f 0x33312d13 0x332fe743 0x3331275b 0x33312425 0x3330d451 0x332e2d79 0x332e1569 0x30b24f1f 0x30b243e7 0x30b22bd7 0x30a8d471 0x30a8d253 0x357c12eb 0x33342845 0x9bb7d 0x3b3b3ab7)
libc++abi.dylib: terminating with uncaught exception of type NSException

甚至可以在用户默认值下存储图像吗?

3 个答案:

答案 0 :(得分:2)

您需要将映像序列化到磁盘,然后在用户默认值中指向该文件。 UIImage符合NSCoding协议,因此您可以使用NSKeyedArchiverNSKeyedUnarchiver序列化图片数据,也可以使用UIImagePNGRepresentation将图片转换为PNG并保存,但效率较低。

答案 1 :(得分:2)

直接在NSUserDefaults中存储图像是不可能的,因为例外情况说,UIImage不是属性列表对象。属性列表是这些对象的组合,只有这些类(或其子类):

  • NSArray
  • NSDictionary
  • NSString
  • NSData
  • NSDate
  • NSNumber

例如,您可以使用NSUserDefaults来存储NSArrayNSString个对象。

从技术上讲,您可以通过将NSData转换为JPEG,PNG或其他标准文件格式来创建UIImage对象,然后将其存储在NSUserDefaults中,如下所示:

UIImage *image = ... ; // your image
CGFloat compressionQuality = 0.8; // the amount of compression, 1.0 being the lowest

NSData *imageData = UIImageJPEGRepresentation(image, compressionQuality);
[[NSUserDefaults standardUserDefaults] setObject:imageData forKey:@"key"];

但你真的不应该这样做。使用UIImageJPEGRepresentation

直接将其写入文件系统可能更好
UIImage *image = ... ; // your image
CGFloat compressionQuality = 0.8; // the amount of compression, 1.0 being the lowest

NSData *imageData = UIImageJPEGRepresentation(image, compressionQuality);

// Get the directories you can write to
N​S​A​r​r​a​y​ ​*​d​o​c​u​m​e​n​t​D​i​r​e​c​t​o​r​i​e​s​ ​=​ ​N​S​S​e​a​r​c​h​P​a​t​h​F​o​r​D​i​r​e​c​t​o​r​i​e​s​I​n​D​o​m​a​i​n​s​(​N​S​D​o​c​u​m​e​n​t​D​i​r​e​c​t​o​r​y​,​ N​S​U​s​e​r​D​o​m​a​i​n​M​a​s​k​, Y​E​S​)​;​
// Get the first one
​N​S​S​t​r​i​n​g​ ​*​d​o​c​u​m​e​n​t​D​i​r​e​c​t​o​r​y​ ​=​ ​[​d​o​c​u​m​e​n​t​D​i​r​e​c​t​o​r​i​e​s​ ​o​b​j​e​c​t​A​t​I​n​d​e​x​:​0​]​;​

NSString *uniqueSuffix = @"something";
NSString *path = [documentDirectory stringByAppendingString:uniqueSuffix];

[imageData writeToFile:path atomically:YES]; // atomically is a bit safer, but slower

或者你可以从UIImage实现NSCoding协议的事实中受益:

@interface TestImageStore () <NSCoding>

@property (strong, nonatomic) UIImage *image1;
@property (strong, nonatomic) UIImage *image2;

@end

@implementation TestImageStore


- (id)initWithCoder:(NSCoder *)aDecoder
{
    self = [super init];
    if (self) {
        self.image1 = [aDecoder decodeObjectForKey:@"image1"];
        self.image2 = [aDecoder decodeObjectForKey:@"image2"];
    }
    return self;
}

- (void)encodeWithCoder:(NSCoder *)aCoder
{
    [aCoder encodeObject:self.image1 forKey:@"image1"];
    [aCoder encodeObject:self.image2 forKey:@"image2"];
}

最后,你也可以使用核心数据,但这肯定比上面概述的方法更复杂。

答案 2 :(得分:1)

您只能在NSUserdefaults中保存一组有限的对象类型,UIImage不是其中之一。我不知道NSUserDefaults的大小限制。 UIImage可以转换为可接受的类型,但请参见下文:

这实际上是在滥用NSUserDefaults。将数据(序列化为数据)保存在文档目录的文件中,如有必要,将文件名保存在NSUserDefaults中。但只是在NSUserDefaults中保存名称是不合适的,这就是CoreData或SQLite或其他文档所针对的目的。

来自Apple文档:

  

NSUserDefaults类提供了便于访问的方法   常见类型,例如浮点数,双精度数,整数,布尔值和URL。一个   默认对象必须是属性列表,即(或   对于集合的实例组合): NSData,NSString,   NSNumber,NSDate,NSArray或NSDictionary 。如果你想存储任何   在其他类型的对象中,通常应将其存档以创建   NSData的实例。