天天看點

無處不在的記憶體洩漏-蘋果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方法不會造成記憶體洩漏,下面我會給出良好的解決方法;

再看看接口

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

原來delegate是strong的,蘋果你咋不按套路出牌,蘋果為什麼要這樣設計呢?不管出于什麼原因,我們都要修複它

- (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委托方法即可。

繼續閱讀