zoukankan      html  css  js  c++  java
  • [iOS]定时器NSTimer、CADisplayLink的内存管理

    NSTimer、CADisplayLink会对target产生强引用,如果target同时对他们产生强引用,则会发生循环引用。

    以NSTimer为例,解决循环引用的问题。

    方法1:使用block

    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
        
        __weak typeof(self) weakself = self;
        self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 repeats:YES block:^(NSTimer * _Nonnull timer) {
            [weakself func];
        }];
    }
    
    - (void)func
    {
        NSLog(@"%s",__func__);
    }
    
    - (void)dealloc
    {
        NSLog(@"%s",__func__);
        [self.timer invalidate];
    }

    方法2:使用NSObject作为中间对象

    Proxy1.h
    
    @interface Proxy1 : NSObject
    + (instancetype)initWithTarget:(id)target;
    @end
    Proxy1.m
    
    @interface Proxy1 ()
    @property (nonatomic,weak) id target;
    @end
    
    @implementation Proxy1
    
    + (instancetype)initWithTarget:(id)target
    {
        Proxy1 *proxy = [[Proxy1 alloc] init];
        proxy.target = target;
        return proxy;
    }
    
    - (id)forwardingTargetForSelector:(SEL)aSelector
    {
        return self.target;
    }
    
    @end
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
        
        self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:[Proxy1 initWithTarget:self] selector:@selector(func) userInfo:nil repeats:YES];
    }
    
    - (void)func
    {
        NSLog(@"%s",__func__);
    }
    
    - (void)dealloc
    {
        NSLog(@"%s",__func__);
        [self.timer invalidate];
    }

    方法3:使用NSProxy作为中间对象

    Proxy2.h
    
    @interface Proxy2 : NSProxy
    + (instancetype)initWithTarget:(id)target;
    @end
    Proxy2.m
    
    @interface Proxy2 ()
    @property (nonatomic,weak) id target;
    @end
    
    @implementation Proxy2
    
    + (instancetype)initWithTarget:(id)target
    {
        Proxy2 *proxy = [Proxy2 alloc];
        proxy.target = target;
        return proxy;
    }
    
    - (NSMethodSignature *)methodSignatureForSelector:(SEL)sel
    {
        return [self.target methodSignatureForSelector:sel];
    }
    
    - (void)forwardInvocation:(NSInvocation *)invocation
    {
        [invocation invokeWithTarget:self.target];
    }
    
    @end
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
        
        self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:[Proxy2 initWithTarget:self] selector:@selector(func) userInfo:nil repeats:YES];
    }
    
    - (void)func
    {
        NSLog(@"%s",__func__);
    }
    
    - (void)dealloc
    {
        NSLog(@"%s",__func__);
        [self.timer invalidate];
    }

    方法3的优点:

    执行效率高,无需执行父类的方法搜索过程,直接进行消息转发。

    关于NSProxy补充:

    通过调用isKindOfClass

    Proxy1 *proxy1 = [Proxy1 initWithTarget:self];
    Proxy2 *proxy2 = [Proxy2 initWithTarget:self];
    
    NSLog(@"%d",[proxy1 isKindOfClass:[ViewController class]]);   // 0
    NSLog(@"%d",[proxy2 isKindOfClass:[ViewController class]]);   // 1

    proxy1为Proxy1类型,Proxy1继承自NSObject,可以正常处理isKindOfClass方法,所以判断结果为0.

    proxy2为Proxy2类型,Proxy2继承自NSProxy,大部分方法会直接进入消息转发阶段,会改为使用target进行调用,所以判断结果为1.

    通过观察NSProxy的源码发现,该方法直接进行了消息转发。

    /**
     * Calls the -forwardInvocation: method to determine if the 'real' object
     * referred to by the proxy is an instance of the specified class.
     * Returns the result.<br />
     * NB. The default operation of -forwardInvocation: is to raise an exception.
     */
    - (BOOL) isKindOfClass: (Class)aClass
    {
        NSMethodSignature    *sig;
        NSInvocation        *inv;
        BOOL            ret;
        
        sig = [self methodSignatureForSelector: _cmd];
        inv = [NSInvocation invocationWithMethodSignature: sig];
        [inv setSelector: _cmd];
        [inv setArgument: &aClass atIndex: 2];
        [self forwardInvocation: inv];
        [inv getReturnValue: &ret];
        return ret;
    }
  • 相关阅读:
    pytorch的函数中的group参数的作用
    pytorch的函数中的dilation参数的作用
    resnet18全连接层改成卷积层
    Pytorch实现UNet例子学习
    MyEclipse中出现Address already in use:JVM_Bind:8080
    为SQL数据库创建登录名和密码
    集合体系
    排序算法及其java实现
    java泛型通配符?
    Arrays.asList的用法
  • 原文地址:https://www.cnblogs.com/EverNight/p/14876063.html
Copyright © 2011-2022 走看看