Block的测试

//输出10
int x = 10;
    void(^function)(void)  = ^(void) {
        printf("-----> %d",x);
    };
    x = 12;
    function();
//输出12
int __block  x = 10;
    void(^function)(void)  = ^(void) {
        printf("-----> %d",x);
    };
    x = 12;
    function();

 上面两个换成NSString一样是这种情况,带__block才会输出后面配置的新值。

//输出ab
int __block x = 10;
    NSMutableString *y = [NSMutableString stringWithString:@"a"];
    void(^function)(void)  = ^(void) {
        printf("-----> %d
",x);
        printf("++++>%s",[y UTF8String]);
    };
    x = 12;
    [y appendString:@"b"];
    function();

可变对象没有问题

//正常输出
const char * text = "hello";
    void(^function)(void)  = ^(void) {
        printf("-----> %d
",x);
        printf("++++>%s",[y UTF8String]);
        [items addObject:@(10)];
        printf("%c",text[2]);
    };
//数组没有实现对数组的截获,无法在Block里面使用数组
const char  text[] = "hello";
    void(^function)(void)  = ^(void) {
        printf("-----> %d
",x);
        printf("++++>%s",[y UTF8String]);
        [items addObject:@(10)];
        printf("%c",text[2]);
    };
@interface YDTestObject : NSObject

@property (nonatomic, strong) YDTestObject *otherObject;
@property (nonatomic, strong) NSString *name;
@property (nonatomic, copy) void (^saveBlock)(void);

- (void)doBlock:(void(^)(void))block;
- (void)doSaveBlock;

@end

@interface ViewController ()

@property (nonatomic, strong) YDTestObject *testObject;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    YDTestObject *testObject = [YDTestObject new];
    testObject.name = @"test";
    YDTestObject *aObject = [YDTestObject new];
    aObject.name = @"a";
    YDTestObject *bObject = [YDTestObject new];
    bObject.name = @"b";
    testObject.otherObject = aObject;
    aObject.otherObject = bObject;
    [testObject setSaveBlock:^{
        [bObject doBlock:^{
            [aObject doBlock:^{
                NSLog(@"xxxxxx");
            }];
        }];
    }];
    [testObject doSaveBlock];
    NSLog(@"测试开始");
}


@end


@implementation YDTestObject

- (void)doBlock:(void (^)(void))block {
    !block?:block();
}

- (void)dealloc {
    NSLog(@"dealloc: %@",self.name);
}

- (void)doSaveBlock {
    !self.saveBlock?:self.saveBlock();
}

@end
2020-11-03 19:34:21.953942+0800 justTestUnknow[14796:83939] xxxxxx
2020-11-03 19:34:21.954051+0800 justTestUnknow[14796:83939] 测试开始
2020-11-03 19:34:21.954124+0800 justTestUnknow[14796:83939] dealloc: test
2020-11-03 19:34:21.954185+0800 justTestUnknow[14796:83939] dealloc: a
2020-11-03 19:34:21.954240+0800 justTestUnknow[14796:83939] dealloc: b

上述调用修改为将无法正常释放,aObject和bObject位置互换也是一样无法释放

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    YDTestObject *testObject = [YDTestObject new];
    testObject.name = @"test";
    YDTestObject *aObject = [YDTestObject new];
    aObject.name = @"a";
    YDTestObject *bObject = [YDTestObject new];
    bObject.name = @"b";
    testObject.otherObject = aObject;
    aObject.otherObject = bObject;
    [bObject setSaveBlock:^{
        [aObject doBlock:^{
            [testObject doBlock:^{
                NSLog(@"xxxxxx");
            }];
        }];
    }];
    [bObject doSaveBlock];
    NSLog(@"测试开始");
}

 再修改为下面的样子,则是都可以释放

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.testObject = [YDTestObject new];
    self.testObject.name = @"test";
    YDTestObject *aObject = [YDTestObject new];
    aObject.name = @"a";
    YDTestObject *bObject = [YDTestObject new];
    bObject.name = @"b";
    self.testObject.otherObject = aObject;
    aObject.otherObject = bObject;
    [aObject setSaveBlock:^{
        [bObject doBlock:^{
            [self.testObject doBlock:^{
                NSLog(@"xxxxxx");
            }];
        }];
    }];
    [aObject doSaveBlock];
    NSLog(@"测试开始");
    self.testObject = nil;
}

再把self改成rootObject那么又无法释放内存了

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    YDTestObject *rootObject = [YDTestObject new];
    rootObject.name = @"root";
    YDTestObject *testObject = [YDTestObject new];
    testObject.name = @"test";
    YDTestObject *aObject = [YDTestObject new];
    aObject.name = @"a";
    YDTestObject *bObject = [YDTestObject new];
    bObject.name = @"b";
    rootObject.otherObject = testObject;
    testObject.otherObject = aObject;
    aObject.otherObject = bObject;
    [aObject setSaveBlock:^{
        [bObject doBlock:^{
            [rootObject.otherObject doBlock:^{
                NSLog(@"xxxxxx");
            }];
        }];
    }];
    [aObject doSaveBlock];
    NSLog(@"测试开始");
}

 再修改一下,又可以正常释放内存了

@interface ViewController ()

@property (nonatomic, strong) YDTestObject *testObject;
@property (nonatomic, strong) YDTestObject *checkObject;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.testObject = [YDTestObject new];
    self.testObject.name = @"test";
    self.checkObject = [YDTestObject new];
    self.checkObject.name = @"a";
    YDTestObject *bObject = [YDTestObject new];
    bObject.name = @"b";
    self.testObject.otherObject = self.checkObject;
    self.checkObject.otherObject = bObject;
    [self.checkObject setSaveBlock:^{
        [bObject doBlock:^{
            [self.testObject doBlock:^{
                NSLog(@"xxxxxx");
            }];
        }];
    }];
    [self.checkObject doSaveBlock];
    NSLog(@"测试开始");
    self.checkObject = nil;
    self.testObject = nil;
}


@end

 如果上面的不写上

self.checkObject = nil;

那么就是只有testObject得到释放了

再改进一下,test和a都释放了,但是b却无法释放

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    [self testFunction];
    [self.checkObject doBlock:^{
        NSLog(@"%@",self.checkObject);
    }];
    [self.checkObject setSaveBlock:^{
        [self.testObject doBlock:^{
            [self.checkObject.otherObject doBlock:^{
                NSLog(@"xxxxxx");
            }];
        }];
    }];
    [self.checkObject doSaveBlock];
    NSLog(@"测试开始");
    self.checkObject = nil;
    self.testObject = nil;
}

- (void)testFunction {
    self.testObject = [YDTestObject new];
    self.testObject.name = @"test";
    self.checkObject = [YDTestObject new];
    self.checkObject.name = @"a";
    self.testObject.otherObject = self.checkObject;
    YDTestObject *bObject = [YDTestObject new];
    bObject.name = @"b";
    self.checkObject.otherObject = bObject;
    [self.checkObject setSaveBlock:^{
        NSLog(@"%@",self.checkObject);
    }];
    [bObject setSaveBlock:^{
        NSLog(@"%@",bObject);
    }];
}

 参照上面引入rootObject,导致循环引用的情况,打破它的循环引用

- (void)test2 {
    YDTestObject *rootObject = [YDTestObject new];
    rootObject.name = @"root";
    YDTestObject *testObject = [YDTestObject new];
    testObject.name = @"test";
    YDTestObject *aObject = [YDTestObject new];
    aObject.name = @"a";
    YDTestObject *bObject = [YDTestObject new];
    bObject.name = @"b";
    rootObject.otherObject = testObject;
    testObject.otherObject = aObject;
    aObject.otherObject = bObject;
    [aObject setSaveBlock:^{
        [bObject doBlock:^{
            [rootObject.otherObject doBlock:^{
                NSLog(@"xxxxxx");
            }];
        }];
    }];
    [aObject doSaveBlock];
    NSLog(@"测试开始");
    //方案一
    rootObject.otherObject = nil;
    //方案二
//    testObject.otherObject = nil;
  //方案三
// aObject.saveBlock = nil; }

解决办法:

aObject引用了saveBlock,saveBlock引用了bObject和rootObject,rootObject引用了testObject

循环引用链是 aObject、aObject.saveBlock、rootObject、testObject、aObject

打破循环引用,断其中一个链接即可,对应上述三个方案

对比与其最相似的self.testObject

起初循环引用链为  aObject、aObject.saveBlock、self、self.testObject、aObject

最后一句self.testObject = nil 相当与将 self 和 self.testObject关联打破,破除了循环引用

原文地址:https://www.cnblogs.com/yuxiaoyiyou/p/11214865.html