// 将 OC 代码转换为 c++ 代买 // xcrun -sdk iphones clong -arch arm64 -rewrite-objc main.m
- block 的原理是怎样的 ? 本质是什么 ?
block 的本事是一个OC 对象,它的内部有isa 指针 block 是封装了函数调用以及函数调用环境的的OC对象
- ++bock 的属性修饰词为什么是copy?使用block有哪些注意的 ?
- block 在修改NSMUtableArray, 需不需要添加__block;
最简单的block ^{} 通过 ^{}(); 加一个小括号调用
一般都是先存起来
返回值void (^block)(参数int,int) = ^(参数int a, int b){};
调用 block(10,10);
Block 的地城结构
`struct __main_block_impl_0 {
struct __block_impl impl {
void *isa (OC 对象的特征 isa指针)
int Flags
int reserved
void *funcPtr; 指向了将要执行代码的地址 (方法的内存地址)
}
// 捕获了外部的局部变量 age 和 *height
int age(auto) 值传递
int *height(static); 指针传递
srtuct __main_block_desc_0 *desc;
{size_t reserved,
size_t Blocksize
}
}`
auto int age = 10; auto 自动变量,离开作用域就消失 static int weight = 100; void(^block)() = ^{ block age 已经把capture 捕获到 他的结构体了 nslog(age) }
// 在这里修改已经被block捕获的变量是无效的 age = 20;
nslog(age)
llbd age is 10;
局部变量 自动变量 auto 值传递 static 指针传递
block为什么要捕获局部变量 ? 因为 自动变量会除了作用域可能会销毁, 所以block 需要强持有,所以需要捕获局部变量,全局变量不需要捕获
-
(void)test {
void ^(block)(void) = ^{ nslog(self); nslog(_name); 如果使用_name 会捕获 self, 因为_name = self->_name; 如果使用self.name 也会捕获self }
block();
此处的self 会被当做局部变量捕获 因为, 方法隐藏的 两个 默认参数 -(void)test:(id) self ) _cmd:(SEL)_com; }
Block 类型 void ^(block)(void) = ^{ nslog(@"1111"); } block 继承 自 NSblock 有三种block 堆 栈区 全局 三种
nslog (@"%@",[block class]);
lldb NSGlobaBlock
nslog (@"%@",[block class] superClass]);
lldb __NSGlobaBlock
nslog (@"%@",[block class] superClass] superClass]);
lldb NSBlock
nslog (@"%@",[block class] superClass] superClass] superClass]);
lldb NSObject
应用内存分布
代码段
全局段
堆段 动态分配内存
栈段
为什么 block 要copy 因为需要把block 保存到堆区 , 防止栈区 被系统自动释放
typedef void (^MyBlock)(Void);
MyBlock myblock () { return [^{ nslog(______) } copy] (ARC 自动追加Copy 操作到堆上)
block 作为返回值的时候回自动copy到堆上
block 赋值给__Strong 指针的时候回自动copy 到堆上
block 作为cocoaAPI中方法名含有 usingBlock的方法参数时会自动拷贝到堆上
block 作为GCD 的方法参数
}
MyBlock block = myblock();
block();
栈block 访问外部auto变量 不会对外边 强引用
堆block 会群分 强弱 引用
访问的对象类型的变量 block 结构体的des 会生成 copy and disspose 在 copy 到 堆区的时候 block 会调用_Block_objc_assign (会根据强弱引用,生成结构体中变量的强弱引用) 在 从对空间释放block的时候 会调用 disspose 函数 释放强引用的变量
值类型 不可被block 修改 static 可以被block 内部修改
__block 不可以修饰全局变量 和 static 变量
__block 修饰的对象 会被 __block_byref_age_0 包装一层成为一个对象类型 __block 修饰的对象 会被 __block_byref_age_0 *age
block_byref_age_ *__forwarding; 指针, 指向的是自己 这个对象
age -> block -> _block_byref_age_0 *age --> block_byref_age *__forwarding -> age
NSMutableArrar *array = [NSMutableArray array];
void (^block) (void) = ^{
如果 arr赋值 需要用__block 修饰
array = nil;
如果 只是使用 就不需要 使用__block
[array addObject:@""]
}
循环引用问题
@interface Person @property (copy, noato) block;
block 和person 相互引用
block = ^{ nslog(person.age); }
// 第一种 __weak Person *weakperson = person;
__weak typrod(self) weakSelf = self;
self.block = ^ { nslog(weakSelf); }
// 第二种
__ block Person *person = [person alloc]init]
block = ^{ nalog(person.age);
person = nil; (这是一种解决循环引用的方案) 但是必须调用block (person.block;)
}
person.block; // 第三种 __unsase_unretained id weakSelf = self; 引用计数器一直不变
self.block = ^ { piint(weakself) }
// 关于stringSelf
// __strong typeof(weakSelf) myself = weakSelf; __weak typrod(self) weakSelf = self;
self.block = ^ { __strong typeof(weakSelf) myself = weakSelf; 保证weak 在使用过程中指针不会挂掉 nslog(weakSelf); }