iOS

block(三)

2019-03-21  本文已影响11人  dandelionYD

引言

我们在前面知道了block内部捕获外部的变量blcok(一)blcok(二)

block_07.png

发现修改不了被捕获的变量

解决:

int main(int argc, const char * argv[]) {
    @autoreleasepool {
      __block int age = 10;
        void (^myBlock)(void) = ^{
            age = 20;
            NSLog(@"age = %d",age);
        };
        myBlock();
        NSLog(@"age = %d",age);
    }
    return 0;
}
打印:
12.__block的使用[34938:11235669] age = 20
12.__block的使用[34938:11235669] age = 20

我们看下底层的c++源码

xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main.cpp

block_08.png

底层:编译器会将__block变量包装成一个对象

#import <Foundation/Foundation.h>
typedef void(^myBlock)(void);
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSMutableArray *arr = [NSMutableArray array];
        myBlock block = ^{
            [arr addObject:@"1"];
            [arr addObject:@"2"];
        };
        block();
        NSLog(@"arr = %@",arr);
    }
    return 0;
}
打印:
13.__block的使用2[35103:11287535] arr = (
    1,
    2
)

不会报错:因为只是来用arr的,而不是来修改arr的(arr = nil)

说明:block在修改NSMutableArray,需不需要添加__block?
为数组增删改的时候不需要
修改指针的对象的时候需要

__block的细节

#import <Foundation/Foundation.h>
struct __block_impl {
    void *isa;
    int Flags;
    int Reserved;
    void *FuncPtr;
};

struct __main_block_desc_0 {
    size_t reserved;
    size_t Block_size;
};

struct __Block_byref_age_0 {
    void *__isa; // 8
    struct __Block_byref_age_0 *__forwarding; //8
    int __flags; //4
    int __size; //4
    int age;
};

struct __main_block_impl_0 {
    struct __block_impl impl;
    struct __main_block_desc_0* Desc;
    struct __Block_byref_age_0 *age; // by ref
};

typedef void(^myBlock)(void);

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        __block int age = 10;
        myBlock block = ^{
            age = 20;
            NSLog(@"%d",age);
        };
        block();
        
        struct __main_block_impl_0 *blockImpl = (__bridge struct __main_block_impl_0*)block;
        NSLog(@"%p",&age);
        NSLog(@"End"); //打个断点
    }
    return 0;
}

打印:
14._ _block细节[35269:11308052] 20
14._ _block细节[35269:11308052] 0x100711318
(lldb) p/x blockImpl->age
(__Block_byref_age_0 *) $0 = 0x0000000100711300
(lldb) p/x &(blockImpl->age->age)
(int *) $1 = 0x0000000100711318
(lldb) p/x &age
(int *) $2 = 0x0000000100711318
(lldb) 

发现:age的地址就是内部结构体的age地址
&age  ==   &(blockImpl->age->age)

(blockImpl->age)的地址 + 8 + 8 + 4 +4 =  (blockImpl->age->age)的地址值

__block的内存管理

block_09.png block_10.png

_ _ block的_forwarding指针

还是以【上述__block细节】代码

我们发现

block_11.png

_ _ block的_forwarding指针:指向的是 自身的isa

block_12.png

对象类型的auto变量、__block变量

对象 BLOCK_FIELD_IS__OBJECT
__block变量 BLOCK_FIELD_IS_BYREF

被__block修饰的对象类型

#import <Foundation/Foundation.h>

@interface myPerson:NSObject
@end
@implementation myPerson
@end

typedef void(^myBlock)(void);

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        myPerson *p = [[myPerson alloc]init];
        __block __weak myPerson *weakP = p;
        
        myBlock blcok = ^{
            NSLog(@"person = %@",weakP);
        };
        blcok();

    }
    return 0;
}

分析见下图:

block_13.png

循环引用

我们看下下面的例子:

#import <Foundation/Foundation.h>
typedef void(^myBlock)(void);
@interface myPerson : NSObject
@property(nonatomic,copy)myBlock block;
@end

#import "myPerson.h"
@implementation myPerson
-(void)dealloc{
    NSLog(@"%s",__FUNCTION__);
}
@end

#import <Foundation/Foundation.h>
#import "myPerson.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        myPerson *p = [[myPerson alloc]init];
        p.block = ^{
            NSLog(@"%@",p);
        };
        NSLog(@"End");
    }
    return 0;
}

发现:p对象并没有被销毁
block_14.png

分析:

p对象里面持有block,而block里面又持有person —>造成了循环引用啦

接下来我们来看看循环引用的解决:【ARC】

#import <Foundation/Foundation.h>
#import "myPerson.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        myPerson *p = [[myPerson alloc]init];
        __weak myPerson *weakP = p;
        p.block = ^{
            NSLog(@"%@",weakP);
        };
        NSLog(@"End");
    }
    return 0;
}
打印:
17.循环引用[35636:11420439] End
17.循环引用[35636:11420439] -[myPerson dealloc]
此时:person对象被释放了
#import <Foundation/Foundation.h>
#import "myPerson.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        myPerson *p = [[myPerson alloc]init];
        __weak typeof(p) weakP = p;
        p.block = ^{
            NSLog(@"%@",weakP);
        };
        NSLog(@"End");  
    }
    return 0;
}
打印:
17.循环引用[35659:11425413] End
17.循环引用[35659:11425413] -[myPerson dealloc]
#import <Foundation/Foundation.h>
#import "myPerson.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        myPerson *p = [[myPerson alloc]init];
        __unsafe_unretained  myPerson * weakP = p;
        p.block = ^{
            NSLog(@"%@",weakP);
        };
        NSLog(@"End");
    }
    return 0;
}
打印:
17.循环引用[35674:11429822] End
17.循环引用[35674:11429822] -[myPerson dealloc]
#import <Foundation/Foundation.h>
#import "myPerson.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        myPerson *p = [[myPerson alloc]init];
        __block  myPerson * weakP = p;
        p.block = ^{
            NSLog(@"%@",weakP);
            weakP = nil;
        };
        p.block();
        NSLog(@"End");
    }
    return 0;
}
注意:必须要调用block才行
打印:
17.循环引用[35724:11431748] <myPerson: 0x1005053c0>
17.循环引用[35724:11431748] End
17.循环引用[35724:11431748] -[myPerson dealloc]

总结:

block_15.png block_16.png

解决循环引用:【MRC】

由于:MRC下不支持__weak

所以 :只有__ unsafe_unretained、__ block方法

mrc下不会对__block的对象进行强引用,所以mrc下不需要置位nil)

#import <Foundation/Foundation.h>
#import "myPerson.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        myPerson *p = [[myPerson alloc]init];
        __unsafe_unretained  myPerson * weakP = p;
        p.block = ^{
            NSLog(@"%@",weakP);
        };
        NSLog(@"End");
    }
    return 0;
}

--------------
#import <Foundation/Foundation.h>
#import "myPerson.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        myPerson *p = [[myPerson alloc]init];
        __block  myPerson * weakP = p;
        p.block = ^{
            NSLog(@"%@",weakP);
        };
        p.block();
        NSLog(@"End");
    }
    return 0;
}

补充:__ weak 和 __ strong

myPerson.h
#import <Foundation/Foundation.h>
typedef void(^myBlock)(void);
@interface myPerson : NSObject
@property(nonatomic,copy)myBlock block;
-(void)run;
@end

myPerson.m
#import "myPerson.h"
@implementation myPerson
-(void)dealloc{
    NSLog(@"%s",__FUNCTION__);
}
-(void)run{
    NSLog(@"run----");
}
@end
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    myPerson *p = [[myPerson alloc]init];
    __weak myPerson *weakP = p;
    p.block = ^{
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            [NSThread sleepForTimeInterval:5];
            NSLog(@"%@",weakP);
            [weakP  run];
        });
    };
    p.block();
    NSLog(@"End");
}
打印:
block2[36791:11582899] End
block2[36791:11582899] -[myPerson dealloc]
block2[36791:11582959] (null)
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    myPerson *p = [[myPerson alloc]init];
    __weak myPerson *weakP = p;
    p.block = ^{
        __strong  myPerson *p = weakP;
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            [NSThread sleepForTimeInterval:5];
            NSLog(@"%@",p);
            [p  run];
        });
    };
    p.block();
    NSLog(@"End");
}
打印:
block2[36767:11581355] End
block2[36767:11581544] <myPerson: 0x600001fc6be0>
block2[36767:11581544] run----
block2[36767:11581544] -[myPerson dealloc]

分析见下图:

block_17.png block_18.png

友情链接:

上一篇下一篇

猜你喜欢

热点阅读