美文网首页
内存管理二之性能优化实战

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

作者: 暗夜精灵_NightElf | 来源:发表于2019-10-28 20:51 被阅读0次

    循环引用:

    案例一:

    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;
    
    }
    

    相关文章

      网友评论

          本文标题:内存管理二之性能优化实战

          本文链接:https://www.haomeiwen.com/subject/ohlivctx.html