无处不在的内存泄漏-苹果BUG?

即使你对自己的技术功底有再多的自信,都请养成使用Instruments工具排查内存泄漏的良好习惯,

即使Instruments再牛逼,你也还要养成看接口文档的良好习惯,因为你防谁也防不了苹果。。。

下面就是使用Instruments排查不出来的内存泄漏


直接上代码

CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"colors"];
[animation setToValue:@[(__bridge id)DX_RGB(170, 127, 245).CGColor, (__bridge id)DX_RGB(137, 215, 244).CGColor,(__bridge id)DX_RGB(245, 214, 234).CGColor]];
[animation setDuration:3.0];
[animation setRemovedOnCompletion:NO];
[animation setFillMode:kCAFillModeForwards];
[animation setDelegate:self];
[gradientLayer addAnimation:animation forKey:@"animateGradient"];

gradientLayer是当前控制器的一个实例变量,最后退出当前视图控制器后,它没有调用dealloc,发生了内存泄漏,因为当前视图控制器和animation构成了强引用环。

将setRemovedOnCompletion改为YES或者屏蔽setDelegate方法不会造成内存泄漏,下面我会给出良好的解决方法;


再看看接口

/* The delegate of the animation. This object is retained for the

 * lifetime of the animation object. Defaults to nil. See below for the

 * supported delegate methods. */


@property(nullable, strong) id <CAAnimationDelegate> delegate;


原来delegate是strong的,苹果你咋不按套路出牌,苹果为什么要这样设计呢?不管出于什么原因,我们都要修复它


/* Called when the animation either completes its active duration or

 * is removed from the object it is attached to (i.e. the layer). 'flag'

 * is true if the animation reached the end of its active duration

 * without being removed. */


- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag;


尝试在这个回调方法中调用

[animation setDelegate:nil];

引发崩溃,信息如下:

*** Terminating app due to uncaught exception 'CAAnimationImmutable', reason: 'attempting to modify read-only animation <CABasicAnimation: 0x1740315c0>'


完美解决方法:

实现分类:

#import <objc/runtime.h>
static void* MyBasicAnimationKey = "MyBasicAnimationKey";

@interface CABasicAnimation(BUG)<CAAnimationDelegate>

- (void)setDebugDelegate:(id)delegate;

@end

@implementation CABasicAnimation(BUG)

- (void)setDebugDelegate:(id)delegate
{
    self.delegate =  self;//将委托指向自己,并实现委托方法
    
     objc_setAssociatedObject(self, MyBasicAnimationKey, delegate, OBJC_ASSOCIATION_ASSIGN);//这里通过对象关联来实现,注意这里必须是OBJC_ASSOCIATION_ASSIGN,而不能用OBJC_ASSOCIATION_RETAIN,否则仍然是强引用环。
}

#pragma mark - CAAnimationDelegate
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
{
    id obj = objc_getAssociatedObject ( self, MyBasicAnimationKey );
    [obj animationDidStop:anim finished:flag];//这里将实现转给关联对象
}

@end

然后在DebugDelegate中实现- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag委托方法即可。


猜你喜欢

转载自blog.csdn.net/junjun150013652/article/details/53897139