Jay*_*ian 2 core-data objective-c uiimageview uiimage
我的应用程序具有呈现有关实体和 UIScrollView 的一些详细信息的视图,其中包含一些相关缩略图的 UIImageViews(全部保存在核心数据中)。当用户按下缩略图时,我获取全尺寸图像(来自核心数据)并将其呈现在 UIImageView 中。这些图像是从设备相机或相册中捕获到 Core Data 的。保存/检索 UIImage 工作正常。按照 Apple 的建议对数据进行标准化,以尽量减少在需要之前加载大对象。
很抱歉这篇很长的帖子,但想要彻底...
核心数据设置:
顶级实体是WalkthruItem与WalkthruItemImage保存缩略图(可转换)和评论的一对多关系。然后将实际的全尺寸图像存储在一对一相关对象中WalkthruItemImageImage,该对象具有称为“图像”的单个可转换属性。这样做是为了防止在显示所有缩略图时加载全尺寸图像。(无法发布编辑器的图像,抱歉)只有在按下缩略图时才会加载全尺寸图像,如下面的代码所示。
问题:
当加载图像(缩略图和全尺寸)时,ImageIO_PNG_Data 永远不会被释放。曾经。即使在内存警告之后。当然,最终的崩溃完美无缺:)
我最终将这些图像加载到 UIImageView 中,然后(我认为)正确释放它们。
未发布的数据在仪器中显示为ImageIO_PNG_Data。通常它们是 14.77 MB,因为它们是由相机(5 秒)捕获的,我认为这是它们完全解压缩的大小。ImageIO_PNG_Data 对象的数量与我加载的唯一图像的数量完全匹配。稍后加载相同的图像不会增加内存占用,因此看起来是 Core Data 试图为我做一些我真的不需要的缓存。
图片加载代码:
这是响应缩略图被按下然后将其放入 UIImageView 的代码。这个案例有点做作,因为我为这个问题简化了它。通常有一个 segue 和一些花哨的 UIImageView 容器,但这种情况以更容易记录的方式显示了确切的内存问题。代码中注释掉了一些失败的修复尝试,并在下面的“我尝试过的”部分中进行了讨论:
if(viewHit.tag>-1){
currentImageIndexForPreview = viewHit.tag;
// this object holds the thumbnail
DCWalkthruItemImage * itemImage = self.walkthruItem.images[currentImageIndexForPreview];
// itemImage.image (1:1 relationship) gets the DCWalkthruItemImageImage object
// itemImage.image.image gets the actual image data
UIImage *image = itemImage.image.image;
// this below attempt doubles the temporarily allocated memory but then frees half of it when the UIImageViews are dealloced
// essentially the same problem but seems to prove that it's not the UIImageView holding the reference
//UIImage *image = [[UIImage alloc] initWithData:UIImagePNGRepresentation(itemImage.image.image)];
// simplified case of just throwing an imageView up on the controller's view
UIImageView* imageView = [[UIImageView alloc] initWithImage:image];
imageView.frame = CGRectMake(testImageViews.count * 10, testImageViews.count * 10, 100, 100);
imageView.contentMode = UIViewContentModeScaleAspectFill;
[self.view addSubview:imageView];
[testImageViews addObject:imageView];
// attempts to free references
itemImage.image.image = nil;
[self.managedObjectContext refreshObject:itemImage.image mergeChanges:false];
}
Run Code Online (Sandbox Code Playgroud)
发布代码:
我只是通过按下按钮来调用此代码以释放 UIImageViews
-(void) cleanup{
LogInfo(@"%d images", testImages.count)
for (UIImageView* imageView in testImageViews){
[imageView removeFromSuperview];
imageView.image = nil;
}
[testImageViews removeAllObjects];;
}
Run Code Online (Sandbox Code Playgroud)
我试过的
UIImage *image = [[UIImage alloc] initWithData:UIImagePNGRepresentation(itemImage.image.image)];Core Data 对象的副本创建图像。这会导致分配的内存翻倍,直到 UIImageViews 被释放,并且正如您所期望的那样释放一半的内存。这似乎证明它不是 UIImageViews 持有额外的内存。(这是在代码中注释的)[managedObjectContext refreshObject:itemImage.image mergeChanges:false]说服 Core Data 我真的不关心这些数据,它可以放手这是变压器代码:
这是在 Core Data 编辑器中属性表的 Transformer Name 属性中设置的。
@interface DCUIImageToNSDataTransformer : NSValueTransformer
@end
#import "DCUIImageToNSDataTransformer.h"
@implementation DCUIImageToNSDataTransformer {
}
+ (Class)transformedValueClass {
return [NSData class];
}
+ (BOOL)allowsReverseTransformation {
return YES;
}
- (id)transformedValue:(id)value {
return UIImagePNGRepresentation(value);
}
- (id)reverseTransformedValue:(id)value {
return [[UIImage alloc] initWithData:value];
}
@end
Run Code Online (Sandbox Code Playgroud)
您需要重置 Core Data 对象,否则它将保留二进制数据。这是为什么在 Core Data 中存储二进制数据不是一个好主意的众多原因之一。您最好将图像存储在磁盘上,并将文件指针保留在 Core Data 本身中。
要重置NSManagedObject您需要调用:
NSManagedObject *myImageObject = ...;
NSManagedObjectContext *moc = ...;
[moc refreshObject:myImageObject mergeChanges:NO];
Run Code Online (Sandbox Code Playgroud)
这会将对象变成错误,并且它的所有值都将从内存中删除。
您还可以强制上下文宽调用刷新-reset上NSManagedObjectContext。
| 归档时间: |
|
| 查看次数: |
1506 次 |
| 最近记录: |