首先,不要在 Core Data 中存储图像(或任何二进制数据);尤其是在 iOS 上。将它存储在磁盘上,然后在 Core Data 中存储对文件位置的引用,您将获得更好的性能。
其次,您的示例代码没有显示您如何将数据放入Core Data。因此很难提出解决方案。
更新
我没有找到有关如何执行此操作的简单参考,所以这里是一个:
图像缓存 Pre iOS 5.0
要在 iOS 5.0 之前的环境中在磁盘上设置图像缓存,您需要首先在实体上创建一个NSString
. 在本例中,我们将命名该属性imageFilename
。一旦完成,我们将要NSManagedObject
为我们的实体创建一个子类,以便我们可以实现辅助方法:
@interface MyEntity : NSManagedObject
@property (nonatomic, retain) NSString *imageFilename;
@property (nonatomic, retain) NSImage *image;
@end
我们将让 Core Data 管理它,imageFilename
因为它是在模型中定义的。但是,我们将实现image
.
@implementation MyEntity
@dynamic imageFilename;
@synthesize image = _image;
- (void)setImage:(UIImage*)image
{
NSString *filename = [self imageFilename];
if (!filename) {
filename = [[NSProcessInfo processInfo] globallyUniqueString];
[self setImageFilename:filename];
}
[_image release];
_image = [image retain];
NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
NSString *filePath = [cachePath stringByAppendingPathComponent:filename];
NSData *data = UIImagePNGRepresentation(image);
NSError *error = nil;
if (![data writeToFile:filePath options:NSDataWritingAtomic error:&error]) {
NSLog(@"Failed to write image to disk: %@\n%@", [error localizedDescription], [error userInfo]);
return;
}
}
将-setImage:
图像保存到磁盘到缓存目录中(注意缓存目录没有备份,在空间不足的情况下可以被系统删除)。如果尚未创建文件名,它会选择一个随机文件名。
故意不存储路径,因为应用程序沙箱的目录可以更改。因此,我们只想将文件名存储在 Core Data 中并解析路径。
我们还在内存中保留对图像的引用,这样如果在该实体的生命周期中再次请求图像,我们就不会撞到磁盘。这就是@synthesize
即使我们正在实现访问器的原因。
请注意,我们将图像以 PNG 格式存储在磁盘上。这可能很昂贵(压缩例程相对较慢),但它使图像保持在通用格式中,这很有用。
- (UIImage*)image
{
if (_image) return _image;
NSString *filename = [self imageFilename];
if (!filename) return nil;
NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
NSString *filePath = [cachePath stringByAppendingPathComponent:filename];
if (![[NSFileManager defaultFileManager] fileExistsAtPath:filePath]) return nil;
_image = [[UIImage alloc] initWithContentsOfFile:filePath];
return _image;
}
的实现-image
几乎是相反的。我们检查是否有文件名;解析完整路径并将图像加载到内存中,然后将其返回给调用者。
- (void)prepareForDeletion
{
[super prepareForDeletion];
NSString *filename = [self imageFilename];
if (!filename) return nil;
NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
NSString *filePath = [cachePath stringByAppendingPathComponent:filename];
NSError *error = nil;
if (![[NSFileManager defaultFileManager] removeItemAtPath:filePath error:&error]) {
NSLog(@"Potential error removing on disk image: %@\n%@", [error localizedDescription], [error userInfo]);
}
}
我们希望保持缓存目录尽可能干净,以免造成空间不足的情况。因此,当要从 Core Data 中删除实体时,我们希望从磁盘中删除文件。删除期间发生的实际错误对我们来说不是致命的问题。这可能是一个错误,因为该文件已被删除或其他原因。此错误没有理由完全失败,但记录它很重要。
- (void)willTurnIntoFault
{
[super willTurnIntoFault];
[_image release], _image = nil;
}
@end
最后,我们实现该-willTurnIntoFault
方法,以便我们可以在该实体的生命周期结束时释放对图像的内存引用。
图片缓存 iOS 5.0+
- 在实体上创建二进制属性。
- 打开“存储在外部记录文件中”位。
- 没有第三步