对Block的一点点认识

2018/10/7 posted in  iOS

如果使用weak修饰block,那么将有可能出现野指针的错误问题

那么strong 和 copy 有什么区别呢?

block本身是像对象一样可以retain,和release。但是,block在创建的时候,它的内存是分配在栈上的,而不是在堆上。他本身的作于域是属于创建时候的作用域,一旦在创建时候的作用域外面调用block将导致程序崩溃。因为栈区的特点就是创建的对象随时可能被销毁,一旦被销毁后续再次调用空对象就可能会造成程序崩溃,在对block进行copy后,block存放在堆区.
使用retain也可以,但是block的retain行为默认是用copy的行为实现的,
因为block变量默认是声明为栈变量的,为了能够在block的声明域外使用,所以要把block拷贝(copy)到堆,所以说为了block属性声明和实际的操作一致,最好声明为copy。

Block防止内存泄漏问题

另外还需要注意的是使用 block 的时候注意到内存泄露的情况,必要的时候要使用 weak 中断两个引用。

关于Block的一点注意 特别是网络请求这块

Block捕获外界变量销毁
我们再进一步想想,Block有个最大的特点是可以访问当前的作用域,我们随便创建一个数组,重复上面操作,是否能够销毁...

- (void)blockDemo {
    NSArray *outsideArray = @[@1, @2, @3];
    
    [self.service requestWithParms:nil WithResult:^(id data, NSError *error) {
        // 处理业务逻辑
        // ...
        
        NSLog(@"Result from block:%@", data);
        NSLog(@"outsideArray :%@", outsideArray);
    }];
}

打印结果:
2018-03-25 19:55:40.997535+0800 NetworkCallback[4970:3641450] NextPageViewController has been dealloc!
2018-03-25 19:55:44.831721+0800 NetworkCallback[4970:3641450] outsideArray :(
    1,
    2,
    3
)

注意,vc先销毁了,但是5s后,这个临时变量竟然还没有销毁。那么这个变量存储在哪里呢?
考虑一下,如果你在Block代码里访问了一个超大的文件,这个文件必然是保存在内存的,然后此时你遇上了网络慢,接口好久没有返回,那么这个超大的文件就会一直占用内存

小结

使用Block无论是否有循环引用的可能,都要使用weakself,来防止vc被持有,而延迟释放
Block会导致对象的生命周期被延长,特别是当某些大文件被Block访问时,有几率导致内存不足