oc 基础 -Block

193 阅读3分钟

// 将 OC 代码转换为 c++ 代买 // xcrun -sdk iphones clong -arch arm64 -rewrite-objc main.m

  1. block 的原理是怎样的 ? 本质是什么 ?

block 的本事是一个OC 对象,它的内部有isa 指针 block 是封装了函数调用以及函数调用环境的的OC对象

  1. ++bock 的属性修饰词为什么是copy?使用block有哪些注意的 ?
  2. 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); }