1

원형 이미지 경로에서 이미지보기를 클릭하고 이미지보기에서 새 이미지를 변경하는 데 필요한 이미지를 클릭하여 애니메이션으로 만듭니다. 내 문제는 이미지 뷰에 할당 된 이미지가 할당 취소되지 않는다는 것입니다. 그리고 애플 리케이션 메모리 경고를 받고 추락. 나는이 문제에 대한 많은 해결책을 서핑하고 시도했지만 사용하지는 않았다. 제 경우에는 Objective 클래스에서 모든 UI 구성 요소를 작성해야합니다. 이미지보기와 애니메이션을 만들기위한 코드를 게시하고 있습니다.iOS UIImageView 메모리가 ARC에서 할당 해제되지 않음

@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 루프에서 무효화를 시도했지만 사용하지 않았습니다. 이 문제를 해결하기 위해 내가 참조 용 이미지보기

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; 
     } 
    } 

에게 추가 스프라이트 리더 코드를 제거하기 위해 사용

Allocation inspector

코드

#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 

제발 도와주세요. 미리 감사드립니다.

+0

이미지 뷰를 카테고리 뷰에 추가하지만 하위 뷰에서 제거 하시겠습니까 ?? 이 subviews은 무엇입니까. 그리고 표시된 코드에서 이미지를 제거하는 위치는 어디입니까 ?? – Janmenjaya

+0

NSArray를 사용하고 있습니다 * subviews = [[self.view viewWithTag : 500] subviews]; 카테고리보기의 모든 하위보기를 가져오고 탭 제스처가 감지 된 이미지를 변경합니다. – ponraj

+0

좋아, 그럼 어디 이미지를 제거하고, 나는 당신이 배열에서 개체를 제거하는 것을 볼 수 있습니다. imageView.image = nil; [imageview removeFromSupreView]와 같은 이미지 및 imageView를 제거하는 코드는 어디에 있습니까? 매번 당신을 도청하는 동안 매번 imageView를 할당하는 것 같아요. 그렇다면 다시 할당하기 전에 이미지를 nil로 만들고 supreView에서 imageView를 제거하십시오. 나는 정확하게 추측 했느냐? – Janmenjaya

답변

2
당신이 +[UIImage imageNamed:]로 사전에 이미지를로드 할 경우 전화 imageView.image = [self.mySprites objectForKey:categoryImage];

으로 그들을로드로, 다음 사전이 처음에 포함 된 모든 이미지, 사전 (가정) self.mySprites에 의해 유지되고있는 것 같습니다

압축 된 png 이미지 만 이미지는 화면에 렌더링 될 때 png에서 비트 맵으로 압축이 풀립니다. 압축 해제 된 이미지는 많은 양의 RAM을 사용합니다 (즉, "ImageIO_PNG_Data"라고 표시된 메모리 사용량). 사전에 유지되면, 압축 해제 된 데이터가 사전에 보관 된 UIImage 오브젝트 내에 보관되므로 새 것을 화면에 렌더링 할 때마다 메모리가 증가합니다.

사용 가능한 옵션 다음 self.mySprites 사전에

  • 스토어 이미지 이름 및 수요에 이미지를로드합니다. +[UIImage imageNamed:]은 내부 RAM 캐싱을 구현하여 처리 속도를 향상 시키므로 캐시가 빨리 지워지지 않기 때문에 이미지가 클 경우 메모리 문제가 발생할 수 있습니다. 이것이 문제인 경우 +[UIImage imageWithContentsOfFile:]을 사용하는 것이 좋지만 RAM에 이미지를 캐시하지 않는 추가 코드가 많이 필요합니다.

  • self.mySpritesNSCache으로 다시 구현하십시오. NSCache은 메모리 압력이 너무 높아질 때 물건을 던지기 시작할 것입니다. 따라서 예상 할 때 이미지가없는 경우를 처리하고 디스크에서로드하십시오 (위의 기술을 사용하여).

+0

즉각적인 응답 @ P- 두 번 주셔서 감사합니다. 실제로 스프라이트 시트 아이콘을 사용하고 있습니다 .Mysprites 스프라이트 리더 클래스에 대한 개체입니다 어디에 imageWithContentsOfFile : 및 CGimageref 사용하고 너무 발표했다. 당신은 내 문제를 해결할 수 있다면 nscache를 사용하는 방법을 말해 줘서 고마워. – ponraj

+0

MySprites 클래스의 코드를 볼 수 있습니까? –

+0

참조 용으로 스프라이트 리더 코드를 추가했습니다. – ponraj

0

CAKeyframeAnimation은 CAAnimation에서 상속받은 CAPropertyAnimation에서 상속됩니다. 당신이 CAAnimation 클래스의 대리자가 표시되는 경우가 선언 될 때 아래 작성된

, 그것은 강력하게 참조 - 애니메이션의

/* 대리자.이 개체는 애니메이션 개체의 수명이 * * 동안 유지됩니다. 기본값은 nil입니다. 지원되는 위임 방법 인 *에 대해서는 아래를 참조하십시오. */

@property (강력한) id delegate;

이제 imageView.layer에 animation 참조를 추가 했으므로 imageView.layer에 대한 참조가 CAAnimation 참조에서 강력하게 유지됩니다.

animation.removedOnCompletion = NO; 당신은 레이어에서 이미지보기 먼저 removeAllAnimations으로 수행 한 다음 이미지보기를 해제하는 경우 완료 그래서

에 레이어에서 애니메이션을 제거하지 않습니다

.

CAAnimation이 강력하게 imageView 참조를 참조 했으므로 (또한 보유 횟수가 늘어 났을 것입니다.) 이미지 뷰를 superview에서 제거한 이유는 보유 수가 여전히 0이 아니기 때문일 수 있습니다. 그래서 누출로 이어진다.

+0

나는 animation.removedOnCompletion = YES를 주려고했는데 애니메이션이 완료되면 removeallanimations를 주었지만 효과는 없었습니다. 다른 작업을 수행해야합니까? . – ponraj

0

animation.removedOnCompletion을 설정하는 특정 요구 사항은 NO = 있는가;

animation.removedOnCompletion 설정 보낸

= YES;

은 메모리 누수와 관련된 문제를 해결할 수 있습니다.

/* 애니메이션 활성 기간을 완료하거나 때 호출 또는 - 아래 그림처럼

+0

나는 너무 시도했지만 아무것도 작동하지 않았다 :( – ponraj

0

대안 적으로, 메모리 누수 문제를 해결하면, CAAnimation의 대리자를 구현하여, '층 이미지 뷰 대응에 해당 애니메이션을 제거 할 *이 첨부 된 개체 (즉, 레이어)에서 제거됩니다. 'flag' * 애니메이션이 활성 기간의 끝에 도달하면 제거됩니다. * 삭제됩니다. */

- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag { 
    if (flag) { 
        NSLog(@"%@", @"The animation is finished. Do something here."); 
    } 

    //Get the reference of the corresponding imageView 
    [imageView.layer removeAnimationForKey:@"animation.trash"]; 
} 

UIView *categoryView = [self.view viewWithTag:500]; 
    NSArray *subviews = [categoryView subviews]; 
    for (UIImageView *subview in subviews) { 
     if(![selectedCategories containsObject:subview.accessibilityHint]){ 
      [subview.layer removeAnimationForKey:@"animation.trash"]; // either this 
      //or// [subview.layer removeAllAnimations]; //alternatively 
      [subview removeFromSuperview]; 
      subview.image = Nil; 
     } 
    } 
+0

없음을 변경하지 당신이 animation.delegate = 자동 설정되어;?? – ponraj

+0

당신의 animationDidStop 메서드가 호출나요 애니메이션이 완료된 후 –

+0

animationDidStop 방법은 점점을 하지만 메모리 문제는 해결되지 않았다. 에드. – ponraj

관련 문제