iOS小知识之NSTimer的循环引用三

语言: CN / TW / HK

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

今天继续了解一下切断target强持有的第三种方法

NSProxy虚基类

NSProxy的作用: - OC不支持多继承,但是它基于运行时机制,可以通过NSProxy来实现伪多继承 - NSProxy和NSObject属于同一级别的类,也可以说是一个虚拟类,只实现了NSObject的协议部分 - NSProxy本质是一个消息转发封装的抽象类,类似一个代理人 可以通过继承NSProxy,并重写以下两个方法实现消息转发

``` - (void)forwardInvocation:(NSInvocation *)invocation;

  • (NSMethodSignature *)methodSignatureForSelector:(SEL)sel; ``` NSProxy除了可以用于多继承,也可以作为切断强持有的中间人 打开LGProxy.h文件,写入以下代码:

```

import

@interface LGProxy : NSProxy

  • (instancetype)proxyWithTransformObject:(id)object;

@end ``` 打开LGProxy.m文件,写入以下代码:

```

import "LGProxy.h"

@interface LGProxy()

@property (nonatomic, weak) id object;

@end @implementation LGProxy

  • (instancetype)proxyWithTransformObject:(id)object{

    LGProxy *proxy = [LGProxy alloc]; proxy.object = object; return proxy; }

  • (NSMethodSignature *)methodSignatureForSelector:(SEL)sel{

    if (!self.object) { NSLog(@"异常收集-stack"); return nil; } return [self.object methodSignatureForSelector:sel]; }

  • (void)forwardInvocation:(NSInvocation *)invocation{

    if (!self.object) { NSLog(@"异常收集-stack"); return; } [invocation invokeWithTarget:self.object]; }

@end ``` LGProxy的调用代码:

``` - (void)viewDidLoad { [super viewDidLoad];

self.proxy = [LGProxy proxyWithTransformObject:self];
self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self.proxy selector:@selector(fireHome) userInfo:nil repeats:YES];

}

  • (void)fireHome{ num++; NSLog(@"hello word - %d",num); }

  • (void)dealloc{ [self.timer invalidate]; self.timer = nil; } ```

  • LGProxy初始化方法,将传入的object赋值给弱引用对象
  • 再UIViewController中,创建LGProxy对象proxy。创建NSTimer对象,将proxy传入target,避免NSTimer对ViewController强持有。
  • 当NSTimer回调时,触发LGProxy的消息转发方法
    • methodSignatureForSelector:设置方法签名
    • forwardInvocation:自身不做业务处理,将消息转发给object
  • 当页面退出时,ViewController可以正常释放
    • 再dealloc中,对NSTimer进行释放。此时NSTimer对proxy的强持有接触,proxy也跟着释放