内存管理二之性能优化实战

循环引用:

案例一:

A持有B

B持有A

如果A释放会发给B一个dealloc但是A要释放的前提是要B释放掉。这样就出现,就产生一个环。

例子:

self.name = "hello"

self.block = ^{

self.name="hello world"

}

解决:

self.name = "hello"

__weak typeof(self) weakSelf = self;

self.block = ^{

      weakSelf.name="hello world"

}

另一种解决:

self.name = "hello"

//self -> block ->vc(nil)->self

__block ViewController *vc = self; //初始化一个临时变理的结构体

self.block = ^{

      vc.name="hello world"

vc  = nil;//这里自己手动释放掉,就打破循环

}

第三种解决:(这种性能最高)

self.name = "hello"

self.blockVc = ^(ViewController *vc){ //直接传参

      vc.name="hello world"

}

self.blockVc(self)

上面只是一般解决:

但是遇到线程的时候 ,还是会有问题,要用strong-weak

self.name = "hello"

__weak typeof(self) weakSelf = self;

self.block = ^{

dispath_after(dispatch_time(DISPATCH_TIME_NOW,(int64_t)(2*NSEC_PER_SEC)),dispatch_getMain_queue(),^{

weakSelf.name="hello world" //这里weakself已经是nil了,所有会崩溃

});

}.

解决:

self.name = "hello"

__weak typeof(self) weakSelf = self;

self.block = ^{

__strong typeof(self) strongSelf=weakSelf; //这里只是个临时变量,只是暂时保留了self引用,出括号外还是会销掉,但是对于线程 运行完才销掉。就达到我们的目的了。

dispath_after(dispatch_time(DISPATCH_TIME_NOW,(int64_t)(2*NSEC_PER_SEC)),dispatch_getMain_queue(),^{

strongSelf.name="hello world" //这里weakself已经是nil了,所有会崩溃

});

}.

案例二:

NStimer的循环引用

self.timer = [NSTimer scheduledTimerWithInterval:1 target:self selector:@selector(hello) userInfo:nil repeats:YES];

-(void)dealloc:{

[self.timer invation];

self.timer =nil;

}

在这里是释放不了,timer会添加runloop

self -> runloop -> timer -> self

解决方案:

在退出视图的时候 我先把timer销掉,下次退出这个控制器的时候 (dealloc时就不用管)这个timer了

-(void didMoveTParentViewController:(UIViewController *) parent{

if(parent == nil){

[self.timer invation];

self.timer =nil;

}

}

第二方案:

引入第三者的变量去解决(self.target)

self.timer = [NSTimer scheduledTimerWithInterval:1 target:self.target selector:@selector(hello) userInfo:nil repeats:YES];

-(void)dealloc:{

[self.timer invation];

self.timer =nil;

}

现在模型变成

self->runloop->timer->self.target(第三者)

target创建一个类(TimerWapper)

实现vc需要的方法selector传进来,然后去调用

-(instancetype) initwithTimeInterval:(NStimeInterval)ti target:(id)target selector:(SEL)aselector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo{

self.target = target;

self.selector = selector;

self.timer = [NSTimer scheduledTimeWithTimeInterval:ti target:self selector:@selector(action) userInfo:userInfo repeats:yesOrNo];

}

-(void)action{

if([self.target respondsToSelector:self.selector]){

[self.target performSelector:self.selector];

}

}

再写一个释放timer

-(void)timerInvalidate{ //这里可以手动释放

[self.timer invalidate];

self.timer = nil;

}

最后VC里改成

self -> timerWapper(这里相互持有,释放不了,但是我们留出timerInvalidate可以自己手动释放,在dealloc里释放掉,然后再释放掉TimerWapper)<-> timer <- runloop

self.target = [TimerWapper initwithTimeInterval:1 target:self selector:@selector(action) userInfo:nil repearts:YES];

-(void)dealloc:{

[self.target timerInvalidate]; //这里对timer释放,就不会持有timer了

}

第三种方案

利用timer的block方式,这种调用,系统自己优化过,就不会产生循环引用了

//在NSTimer里target就自己(NSTimer)这样就不会循环引用了,[https://www.jianshu.com/p/823ef4fb63bc](https://www.jianshu.com/p/823ef4fb63bc)

self.timer = [NSTimer scheduledTimerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer){

}];

第四种方案(同样适用于 通知的循环引用)

利用代理Proxy与第二种类似

把target调用变成自己的Proxy

Proxy里面不用重写方法,直接 调用runtime的消息转发

+(instancetype)proxyWithTransformObject:(id)object{

Proxy *proxy = [Proxy alloc];

proxy.object=object;

return proxy;

}

//消息转发出去

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

return [self.object methodSignatureForSelector:sel];

}

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

[invocation invokeWithTarget:self.object];

}

最后VC改成

//self->timer<-runloop

// |

//     proxy

self.proxy = [Proxy proxyWithTransformObject:self];

self.timer = [NSTimer scheduledTimerWithInterval:1 target:self.proxy selector:@selector(hello) userInfo:nil repeats:YES];

-(void)dealloc:{

[self.timer invation]; //这里断掉timer引用

self.timer =nil;

}

你可能感兴趣的:(内存管理二之性能优化实战)