当前位置: 首页 > 工具软件 > iOS Block UI > 使用案例 >

iOS底层系列之<11>--Block(四)对象类型的auto变量

夏侯和韵
2023-12-01

一、窥探本质

1、看代码(ARC环境)

#import <Foundation/Foundation.h>
#import "Person.h"
 typedef void (^Block)(void);

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Block block;
        {
            Person *person = [[Person alloc] init];
            person.age = 10;
            block = ^{
                NSLog(@"--%d",person.age);
            };
        }
        NSLog(@"---");
    }
    return 0;
}

打印结果:
2022-01-02 09:38:21.647450+0800 block[47069:12449027] —
2022-01-02 09:38:21.648386+0800 block[47069:12449027] 释放Person对象
Program ended with exit code: 0

  • Person对象被强引用没有被释放

2、MRC环境下

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

 typedef void (^Block)(void);

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Block block;
        {
            Person *person = [[Person alloc] init];
            person.age = 10;
            
            block = ^{
                NSLog(@"--%d",person.age);
            };
            
            [person release]; // MRC环境下,需要手动释放一次
        }
        NSLog(@"---");
    }
    return 0;
}

打印结果:大括号一结束,Person就销毁了
2022-01-04 11:37:14.050683+0800 block[67246:3606713] Person–销毁
2022-01-04 11:37:14.051047+0800 block[67246:3606713] —
Program ended with exit code: 0
说明:
1、此刻的block是在栈里面(点我查看block类型分析
2、当把block放到堆里面去,增加一次copy:

  • __weak问题解决

在使用clang转换OC为C++代码是,可能会报错:
cannot creat __weak reference in file using manual reference
解决方法:
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc -fobjc-arc -fobjc-runtime=ios-8.0.0 main.m

看下面的代码

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

 typedef void (^Block)(void);

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Block block;
        {
            Person *person = [[Person alloc] init];
            person.age = 10;
            
            block = [^{
                NSLog(@"--%d",person.age);
            } copy]; // 增加一次copy,把block放到堆里面去
            
            [person release]; // MRC环境下,需要手动释放一次
        }
        NSLog(@"---");
    }
    return 0;
}

打印结果:2022-01-04 11:44:49.351354+0800 block[67560:3611589] —
Program ended with exit code: 0
说明:
此刻block在堆里面,但是person没有被释放

小结:
当block在栈空间的时候,不会对堆空间的对象持有;当block在堆空间的时候,会对堆空间的对象持有。

3、对象类型的auto变量

  • 当block内部访问了对象类型的auto变量时
    1、如果block是在栈上,将不会对auto变量产生强引用
    2、如果block是被拷贝到堆上

    (a) 会调用block内部的copy函数
    (b) copy函数内部会调用_Block_object_assign函数
    © _Block_object_assign函数会根据auto变量的修饰符(__Strong、__weak、__unsafe_unretain)做出相应的操作,类似于retain(形成强引用、弱引用)

3、如果block从堆上移除
(a) 会调用block内部的dispose函数
(b) dispose函数内部会调用_Block_object_dispose函数
© _Block_object_dispose函数会自动释放引用的auto变量,类似于release

函数调用时间
copy函数栈上的Block复制到堆时
dispose函数堆上的Block被废弃时

4、释放时间

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    Person *person = [[Person alloc] init];
    
    __weak Person *weakPerson = person;
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"强引用--p--%@",person);
        
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@"弱引用--p--%@",weakPerson);
            
        });
    });
    NSLog(@"开始点击");
}

打印:
2022-01-04 17:19:23.200688+0800 02-kvc[82973:3816167] 开始点击
2022-01-04 17:19:24.294069+0800 02-kvc[82973:3816167] 强引用–p--<Person: 0x600002017820>
2022-01-04 17:19:24.294171+0800 02-kvc[82973:3816167] Person–释放
2022-01-04 17:19:26.446509+0800 02-kvc[82973:3816167] 弱引用–p--(null)

5、block修饰

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

 typedef void (^Block)(void);

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // array不需要加__block修饰
        // 是拿这个指针来用,不是对他进行赋值
        NSMutableArray *array = [NSMutableArray array]; 
        
        __block int age = 10;
        __block Person *person = [[Person alloc] init];
        
        Block block = ^{
            [array addObject:@"123"];
            age = 20;
            person.age = 3;
        };
        
        block();
    }
    return 0;
}
  • 转成C++
struct __Block_byref_age_0 {
  void *__isa;
__Block_byref_age_0 *__forwarding; // 这个指针指向自己
 int __flags;
 int __size;
 int age;
};
struct __Block_byref_person_1 {
  void *__isa;
__Block_byref_person_1 *__forwarding;
 int __flags;
 int __size;
 void (*__Block_byref_id_object_copy)(void*, void*);
 void (*__Block_byref_id_object_dispose)(void*);
 Person *__strong person;
};
 类似资料: