强引用(强持有)

简介: 强引用(强持有)

强引用(强持有)


解决NSTimer强引用:


  • 重写didMoveToParentViewController方法


- (void)didMoveToParentViewController:(UIViewController *)parent{  
    // 无论push 进来 还是 pop 出去 正常跑  
    // 就算继续push 到下一层 pop 回去还是继续  
    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 出去 正常跑  
    // 就算继续push 到下一层 pop 回去还是继续  
    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,即监听自己  
            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发送selector消息,并将此时的timer参数也一并传入,所以vc就可以得知`fireHome`方法,就这事这种方式定时器方法能够执行的原因
        //objc_msgSend发送消息,执行定时器方法  
        void (*lg_msgSend)(void *,SEL, id) = (void *)objc_msgSend;  
         lg_msgSend((__bridge void *)(wapper.target), wapper.aSelector,wapper.timer);  
    }else{  
        //如果target不存在,已经释放了,则释放当前的timerWrapper  
        [wapper.timer invalidate];  
        wapper.timer = nil;  
    }  
}  
//在vc的dealloc方法中调用,通过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;  
}




目录
相关文章
|
3月前
|
存储 监控 安全
深入理解ThreadLocal:线程局部变量的机制与应用
在Java的多线程编程中,`ThreadLocal`变量提供了一种线程安全的解决方案,允许每个线程拥有自己的变量副本,从而避免了线程间的数据竞争。本文将深入探讨`ThreadLocal`的工作原理、使用方法以及在实际开发中的应用场景。
107 2
|
3月前
|
存储 Java 程序员
深入理解ThreadLocal及其弱引用
深入理解ThreadLocal及其弱引用
|
9月前
|
Java
【JVM】深入理解Java引用类型:强引用、软引用、弱引用和虚引用
【JVM】深入理解Java引用类型:强引用、软引用、弱引用和虚引用
555 0
|
9月前
|
缓存 Java 程序员
Java垃圾回收: 什么是强引用、软引用、弱引用和虚引用?
Java垃圾回收: 什么是强引用、软引用、弱引用和虚引用?
87 2
|
Java
JVM学习日志(八) 强引用,软引用,弱引用,虚引用
强引用,软引用,弱引用,虚引用 简述
110 0
JVM学习日志(八) 强引用,软引用,弱引用,虚引用
|
Java
强引用、软引用、弱引用、虚引用的区别?
强引用、软引用、弱引用、虚引用的区别?
93 0
|
Java 编译器 Android开发
普通内部类持有外部类引用的原理
内部类虽然和外部类写在同一个文件中, 但是编译完成后, 还是生成各自的class文件,内部类通过this访问外部类的成员。 1、编译器自动为内部类添加一个成员变量, 这个成员变量的类型和外部类的类型相同, 这个成员变量就是指向外部类对象(this)的引用; 2、编译器自动为内部类的构造方法添加一个参数, 参数的类型是外部类的类型, 在构造方法内部使用这个参数为内部类中添加的成员变量赋值; 3、在调用内部类的构造函数初始化内部类对象时,会默认传入外部类的引用。
|
缓存 Java 关系型数据库
强引用、软引用、弱引用、幻象引用有什么区别和使用场景
强引用、软引用、弱引用、幻象引用有什么区别和使用场景
236 1
ThreadLocal线程并发时解决共享变量
ThreadLocal线程并发时解决共享变量
107 0
|
缓存 Java
强引用,软引用,弱引用,幻象引用有什么区别?
强引用,软引用,弱引用,幻象引用有什么区别?
145 0
强引用,软引用,弱引用,幻象引用有什么区别?