強引用(強持有)

強引用(強持有)

解決NSTimer強引用:

  • 重寫didMoveToParentViewController方法
- (void)didMoveToParentViewController:(UIViewController *)parent{  
    // 無論push 進來 還是 pop 出去 正常跑  
    // 就算繼續(xù)push 到下一層 pop 回去還是繼續(xù)  
    if (parent == nil) {  
       [self.timer invalidate];  
        self.timer = nil;  
        NSLog(@"timer 走了");  
    }  
}  
  • 定義timer時,采用閉包的形式,因此不需要指定target
- (void)blockTimer{  
    self.timer = [NSTimer scheduledTimerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {  
        NSLog(@"timer fire - %@",timer);  
    }];  
}  

解決 強引用(強持有)

依賴中介者模式,打破強持有,其中推薦思路四

1. pop時在其他方法中銷毀timer

- (void)didMoveToParentViewController:(UIViewController *)parent{  
    // 無論push 進來 還是 pop 出去 正常跑  
    // 就算繼續(xù)push 到下一層 pop 回去還是繼續(xù)  
    if (parent == nil) {  
       [self.timer invalidate];  
        self.timer = nil;  
        NSLog(@"timer 走了");  
    }  
}  

2.中介者模式,即不使用self,依賴于其他對象

//**********1、定義其他對象**********  
@property (nonatomic, strong) id            target;  

//**********1、修改target**********  
self.target = [[NSObject alloc] init];  
class_addMethod([NSObject class], @selector(fireHome), (IMP)fireHomeObjc, "v@:");  
self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self.target selector:@selector(fireHome) userInfo:nil repeats:YES];  

//**********3、imp**********  
void fireHomeObjc(id obj){  
    NSLog(@"%s -- %@",__func__,obj);  
}  

- (void)dealloc{  
    [self.timer invalidate];  
    self.timer = nil;  
    NSLog(@"%s",__func__);  
}  

3.自定義封裝timer

//*********** .h文件 ***********  
@interface CJLTimerWapper : NSObject  

- (instancetype)cjl_initWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;  
- (void)cjl_invalidate;  

@end  

//*********** .m文件 ***********  
#import "CJLTimerWapper.h"  
#import <objc/message.h>  

@interface CJLTimerWapper ()  

@property(nonatomic, weak) id target;  
@property(nonatomic, assign) SEL aSelector;  
@property(nonatomic, strong) NSTimer *timer;  

@end  

@implementation CJLTimerWapper  

- (instancetype)cjl_initWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo{  
    if (self == [super init]) {  
        //傳入vc  
        self.target = aTarget;  
        //傳入的定時器方法  
        self.aSelector = aSelector;  
         
        if ([self.target respondsToSelector:self.aSelector]) {  
            Method method = class_getInstanceMethod([self.target class], aSelector);  
            const char *type = method_getTypeEncoding(method);  
            //給timerWapper添加方法  
            class_addMethod([self class], aSelector, (IMP)fireHomeWapper, type);  
            
            //啟動一個timer,target是self,即監(jiān)聽自己  
            self.timer = [NSTimer scheduledTimerWithTimeInterval:ti target:self selector:aSelector userInfo:userInfo repeats:yesOrNo];  
        }  
    }  
    return self;  
}  

//一直跑runloop  
void fireHomeWapper(CJLTimerWapper *wapper){  
    //判斷target是否存在  
    if (wapper.target) {  
        //如果存在則需要讓vc知道,即向傳入的target發(fā)送selector消息,并將此時的timer參數(shù)也一并傳入,所以vc就可以得知`fireHome`方法,就這事這種方式定時器方法能夠執(zhí)行的原因
        //objc_msgSend發(fā)送消息,執(zhí)行定時器方法  
        void (*lg_msgSend)(void *,SEL, id) = (void *)objc_msgSend;  
         lg_msgSend((__bridge void *)(wapper.target), wapper.aSelector,wapper.timer);  
    }else{  
        //如果target不存在,已經(jīng)釋放了,則釋放當(dāng)前的timerWrapper  
        [wapper.timer invalidate];  
        wapper.timer = nil;  
    }  
}  

//在vc的dealloc方法中調(diào)用,通過vc釋放,從而讓timer釋放  
- (void)cjl_invalidate{  
    [self.timer invalidate];  
    self.timer = nil;  
}  

- (void)dealloc  
{
    NSLog(@"%s",__func__);  
}  

@end  

4. 利用NSProxy虛基類的子類

//************NSProxy子類************  
@interface CJLProxy : NSProxy  
+ (instancetype)proxyWithTransformObject:(id)object;  
@end  

@interface CJLProxy()  
@property (nonatomic, weak) id object;  
@end  

@implementation CJLProxy  
+ (instancetype)proxyWithTransformObject:(id)object{  
    CJLProxy *proxy = [CJLProxy alloc];  
    proxy.object = object;  
    return proxy;  
}  
-(id)forwardingTargetForSelector:(SEL)aSelector {  
    return self.object;     
}  

//************解決timer強持有問題************  
self.proxy = [CJLProxy proxyWithTransformObject:self];  
self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self.proxy selector:@selector(fireHome) userInfo:nil repeats:YES];  

//在dealloc中將timer正常釋放  
- (void)dealloc{  
    [self.timer invalidate];  
    self.timer = nil;  
}  
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容