我想在圆形路径中为 ImageView 设置动画,并在单击图像时 ImageView 需要更改新图像。我的问题是我分配给 ImageView 的图像没有被释放。并且应用程序收到内存警告并崩溃。我浏览并尝试了很多解决这个问题的方法,但没有用。在我的例子中,我需要从 Objective c 类创建所有 ui 组件。这里发布创建 ImageView 和动画的代码。
@autoreleasepool {
for(int i= 0 ; i < categories.count; i++)
{
NSString *categoryImage = [NSString stringWithFormat:@"%@_%ld.png",[categories objectAtIndex:i],(long)rating];
if (paginationClicked) {
if([selectedCategories containsObject:[categories objectAtIndex:i]]){
categoryImage = [NSString stringWithFormat:@"sel_%@",categoryImage];
}
}
UIImageView *imageView = [[UIImageView alloc] init];
imageView.image = [self.mySprites objectForKey:categoryImage];
imageView.contentMode = UIViewContentModeScaleAspectFit;
imageView.clipsToBounds = NO;
[imageView sizeToFit];
imageView.accessibilityHint = [categories objectAtIndex:i];
// imageView.frame = CGRectMake(location.x+sin(M_PI/2.5)*(self.view.frame.size.width*1.5),location.y+cos(M_PI/2.5)*(self.view.frame.size.width*1.5) , 150, 150);
imageView.userInteractionEnabled = YES;
imageView.multipleTouchEnabled = YES;
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self
action:@selector(categoryTapGestureCaptured:)];
singleTap.numberOfTapsRequired = 1;
[imageView addGestureRecognizer:singleTap];
[categoryView addSubview:imageView];
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
UIBezierPath *path = [UIBezierPath bezierPath];
[path addArcWithCenter:location
radius:self.view.frame.size.width*1.5
startAngle:0.8
endAngle:-0.3+(0.1*(i+1))
clockwise:NO];
animation.path = path.CGPath;
imageView.center = path.currentPoint;
animation.fillMode = kCAFillModeForwards;
animation.removedOnCompletion = NO;
animation.duration = 1+0.25*i;
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
// Apply it
[imageView.layer addAnimation:animation forKey:@"animation.trash"];
}
}
这是在点击时更改图像的代码。
for (UIImageView *subview in subviews) {
NSString *key = [NSString stringWithFormat:@"%@_%ld.png",subview.accessibilityHint,(long)rating];
if ([SelectedCategory isEqualToString:subview.accessibilityHint]) {
NSString *tempSubCategory = [categoryObj objectForKey:SelectedCategory];
if([selectedCategories containsObject:SelectedCategory]){
subview.image = [self.mySprites objectForKey:key];
[selectedCategories removeObject:SelectedCategory];
if (tempSubCategory.length != 0) {
subCategoriesAvailable = subCategoriesAvailable-1;
}
[self showNoPagination:subCategoriesAvailable+2];
}else{
if(selectedCategories.count != 2){
key = [NSString stringWithFormat:@"sel_%@",key];
subview.image = [self.mySprites objectForKey:key];
[selectedCategories addObject:SelectedCategory];
if ([SelectedCategory isEqualToString:@"Other"]) {
[self showCommentDialog];
}else{
if (tempSubCategory.length != 0) {
subCategoriesAvailable = subCategoriesAvailable+1;
}
[self showNoPagination:subCategoriesAvailable+2];
}
}
}
[self disableCategories];
break;
}
}
而且我不知道这里做错了什么。我尝试使 for 循环无效,但没有用。
我用来删除 ImageView 的代码
UIView *categoryView = [self.view viewWithTag:500];
NSArray *subviews = [categoryView subviews];
for (UIImageView *subview in subviews) {
if(![selectedCategories containsObject:subview.accessibilityHint]){
[subview removeFromSuperview];
subview.image = Nil;
}
}
添加 Sprite 阅读器代码以供引用
#import "UIImage+Sprite.h"
#import "XMLReader.h"
@implementation UIImage (Sprite)
+ (NSDictionary*)spritesWithContentsOfFile:(NSString*)filename
{
CGFloat scale = [UIScreen mainScreen].scale;
NSString* file = [filename stringByDeletingPathExtension];
if ([[UIScreen mainScreen] respondsToSelector:@selector(displayLinkWithTarget:selector:)] &&
(scale == 2.0))
{
file = [NSString stringWithFormat:@"%@@2x", file];
}
NSString* extension = [filename pathExtension];
NSData* data = [NSData dataWithContentsOfFile:[NSString stringWithFormat:@"%@.%@", file,extension]];
NSError* error = nil;
NSDictionary* xmlDictionary = [XMLReader dictionaryForXMLData:data error:&error];
NSDictionary* xmlTextureAtlas = [xmlDictionary objectForKey:@"TextureAtlas"];
UIImage* image = [UIImage imageWithContentsOfFile:[NSString stringWithFormat:@"%@.%@", file,[[xmlTextureAtlas objectForKey:@"imagePath"]pathExtension]]];
CGSize size = CGSizeMake([[xmlTextureAtlas objectForKey:@"width"] integerValue],
[[xmlTextureAtlas objectForKey:@"height"] integerValue]);
if (!image || CGSizeEqualToSize(size, CGSizeZero)) return nil;
CGImageRef spriteSheet = [image CGImage];
NSMutableDictionary* tempDictionary = [[NSMutableDictionary alloc] init];
NSArray* xmlSprites = [xmlTextureAtlas objectForKey:@"sprite"];
for (NSDictionary* xmlSprite in xmlSprites)
{
CGRect unscaledRect = CGRectMake([[xmlSprite objectForKey:@"x"] integerValue],
[[xmlSprite objectForKey:@"y"] integerValue],
[[xmlSprite objectForKey:@"w"] integerValue],
[[xmlSprite objectForKey:@"h"] integerValue]);
CGImageRef sprite = CGImageCreateWithImageInRect(spriteSheet, unscaledRect);
// If this is a @2x image it is twice as big as it should be.
// Take care to consider the scale factor here.
[tempDictionary setObject:[UIImage imageWithCGImage:sprite scale:scale orientation:UIImageOrientationUp] forKey:[xmlSprite objectForKey:@"n"]];
CGImageRelease(sprite);
}
return [NSDictionary dictionaryWithDictionary:tempDictionary];
}
@end
请帮我解决这个问题。提前致谢。
最佳答案
看起来所有图像都被字典(假设)self.mySprites
保留,因为您正在通过调用 imageView.image = [self.mySprites objectForKey: categoryImage];
如果您使用 +[UIImage imageNamed:]
将图像加载到字典中,那么字典最初只包含压缩的 png 图像。图像在呈现到屏幕时从 png 解压缩为位图,并且这些解压缩的图像使用大量 RAM(这是您看到的标记为“ImageIO_PNG_Data”的内存使用情况)。如果字典保留了它们,那么每次在屏幕上呈现一个新数据时内存都会增加,因为解压缩的数据保存在字典保留的 UIImage
对象中。
可供您选择的选项:
将图像名称存储在
self.mySprites
字典中,并按需加载图像。您应该知道+[UIImage imageNamed:]
实现了内部 RAM 缓存以加快速度,因此如果图像很大,这也可能会导致内存问题,因为缓存不会很快清除.如果这是一个问题,请考虑使用+[UIImage imageWithContentsOfFile:]
,尽管它需要一些额外的代码(不多),它不会在 RAM 中缓存图像。将
self.mySprites
重新实现为NSCache
。当内存压力过高时,NSCache
将开始抛出一些东西,因此您需要处理图像在您期望的时候不存在的情况,并从磁盘加载它(也许使用上述技术)
关于iOS UIImageView 内存未在 ARC 上释放,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27524198/