如何在其中一个子视图动画时取消分配UIView?

时间:2014-12-11 20:06:31

标签: ios objective-c cocoa-touch uiview memory-leaks

enter image description here --------> enter image description here

我正在尝试创建自定义UIActivityIndicatorView。自定义视图应该与标准视图完全相同,除了它旋转的图像看起来不同。我注意到我的自定义视图在以下测试代码中从超级视图中删除时不会解除分配:

ActivityIndicatorCustomView* v = [[ActivityIndicatorCustomView alloc] initWithFrame:CGRectMake(50.0f, 50.0f, 100.0f, 100.0f)];
[[UIApplication sharedApplication].keyWindow addSubview:v];
[v removeFromSuperview];

罪魁祸首是动画块,因为当它被注释掉时,会调用dealloc。我认为这是一个保留周期,但我不知道如何解决这个问题。

ActivityIndi​​catorCustomView.h

#import <UIKit/UIKit.h>

@interface ActivityIndicatorCustomView : UIView

@property(nonatomic, assign, readonly) BOOL isAnimating;

- (void)startAnimating;
- (void)stopAnimating;

@end

ActivityIndi​​catorCustomView.m

static const NSTimeInterval ANIMATION_PERIOD_HALF_LIFE = 1.0f;

#import "ActivityIndicatorCustomView.h"

@interface ActivityIndicatorCustomView ()

@property(nonatomic, strong) UIImageView* imageView;
@property(nonatomic, assign, readwrite) BOOL isAnimating;

- (void)animateWithTransform:(CGAffineTransform)transform;

@end

@implementation ActivityIndicatorCustomView

#pragma mark NSObject

- (void)dealloc
{
    NSLog(@"dealloc");
}

#pragma mark UIView

- (id)initWithFrame:(CGRect)frame
{
    if (self = [super initWithFrame:frame]) {
        self.imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"activityIndicatorCustom"]];
        self.imageView.frame = self.bounds;
        [self addSubview:self.imageView];
    }

    return self;
}

- (void)didMoveToSuperview
{
    if (!self.hidden && self.superview != nil) {
        [self startAnimating];
    }
}

- (void)willMoveToSuperview:(UIView *)newSuperview
{    
    if (newSuperview == nil) {
        [self stopAnimating];
    }
}

- (void)setHidden:(BOOL)hidden
{
    if (hidden) {
        [self stopAnimating];
    } else if (self.superview != nil) {
        [self startAnimating];
    }

    [super setHidden:hidden];
}

#pragma mark ActivityIndicatorCustomView 

- (void)startAnimating
{
    if (self.isAnimating) {
        return;
    }

    self.isAnimating = YES;
    [self animateWithTransform:CGAffineTransformMakeRotation((CGFloat)M_PI)];
}

- (void)stopAnimating
{
    [self.imageView.layer removeAllAnimations];
    self.isAnimating = NO;
}

#pragma mark ()

- (void)animateWithTransform:(CGAffineTransform)transform
{
    // Must split the animation into two semi-circles. If 
    // you attempt to rotate a full circle, nothing will
    // happen.
    __block ActivityIndicatorCustomView* weakSelf = self;

    [UIView
        animateWithDuration:ANIMATION_PERIOD_HALF_LIFE
        delay:0.0
        options:UIViewAnimationOptionCurveLinear
        animations:^{
            weakSelf.imageView.transform = transform;
        } completion:^(BOOL finished) {
            [weakSelf animateWithTransform:CGAffineTransformIsIdentity(transform)
                ? CGAffineTransformMakeRotation((CGFloat)M_PI)
                : CGAffineTransformIdentity
            ];
        }
    ];
}

@end

2 个答案:

答案 0 :(得分:2)

我在块中保留了bad tutorial个保留周期。它告诉我要做

__block MyViewController *weakSelf = self;

这是错误的。要创建弱引用,我应该这样做:

__weak ActivityIndicatorCustomView* weakSelf = self;

[UIView
    animateWithDuration:ANIMATION_PERIOD_HALF_LIFE
    delay:0.0
    options:UIViewAnimationOptionCurveLinear
    animations:^{
        weakSelf.imageView.transform = transform;
    } completion:^(BOOL finished) {
        [weakSelf animateWithTransform:CGAffineTransformIsIdentity(transform)
            ? CGAffineTransformMakeRotation((CGFloat)M_PI)
            : CGAffineTransformIdentity
        ];
    }
];

答案 1 :(得分:0)

我认为这是因为您在完成块中继续动画(并在下一个[self animateWithTransform:]调用中保留self)。例如,尝试检查超级视图以决定是否继续制作动画:

completion:^(BOOL finished) {
        if (self.superview) {
            [self animateWithTransform:CGAffineTransformIsIdentity(transform)
                ? CGAffineTransformMakeRotation((CGFloat)M_PI)
                : CGAffineTransformIdentity
            ];
         }
    }