Block使用方法总结

- block 本质

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

- block 内调用局部变量和全局变量的原理:

1、block内调用局部变量时:会把局部变量捕获到block内,也就是block内会创建一个对象来接收局部变量,比如局部变量是int a;那么block内就会也创建一个int a;来接收外面的局部变量,这时接收的是这个局部变量的值,那么后面再在block外面改变这个局部变量的值,block里面的这个局部变量的值也不会变了,因为block里面调用的局部变量a是从内部创建的a里取的值。如果局部变量前面加了一个static修饰,那么这时block里面创建的就是这个局部变量的指针也就是地址用来接收这个局部变量的地址,所以这个时候block里面调用这个局部变量时就是调用的地址,这时后面再修改局部变量的值那么地址里面的值也会变。
2、block内调用全局变量时:不会把全局变量捕获到block内,是直接调用全局变量,所以后面改变全局变量的值那么block里也会改变

成员变量属于局部变量,self属于局部变量
成员变量:@property (nonatomic, copy) NSArray *imagesArray;

@implementation MineVC
int a = 10;//写在这是全局变量
 - (void)text{
int b = 10;//写在这是局部变量 
}
@end

- block的copy

1、在ARC环境下,编译器会根据情况自动将栈上的block复制到堆上,比如以下情况:
(1)block作为函数返回值时
(2)将block赋值给__strong指针时
(3)block作为 Cocoa API 中,方法名里含有usingBlock的方法参数时
(4)block作为 GCD API 的方法参数时
2、MRC下block属性的建议写法
@property(copy,nonatomic)void(^block)(void);
3、ARC下block属性的建议写法
@property(strong,nonatomic)void(^block)(void);
@property(copy,nonatomic)void(^block)(void);

- 对象类型的auto变量

1、当block内部访问了对象类型的auto变量时
(1)如果block是在栈上,将不会对auto变量产生强引用
(2)如果block被拷贝到堆上
1>会调用block内部的copy函数
2>copy函数内部会调用_Block_object_assign函数
3>_Block_object_assign函数会根据auto变量的修饰符(__strong、__weak、__unsafe_unretained)作出相应的操作,类似于regain(形成强引用、弱引用)
(3)如果block从堆上移除
1>会调用block内部的dispose函数
2>dispose函数内部会调用_Block_object_dispose函数
3>_Block_object_dispose函数会自动释放引用的auto变量,类似于release

typedef void (^MJBlock)(void);
int main(int argc, const char * argv[]) {//主函数
	@autoreleasepool {
		int age = 10;
		MJBlock block = ^{
 			age = 20;//这样写是错误的,因为 int age = 10;这个age是在main函数里面的(内存也就存在main函数这个栈空间里),而block方法其本质是在function这个函数里执行的,你不可能在一个函数里去调用另外一个函数里的局部变量。那么怎么在block里面修改这个age呐,方法一:在int前面加一个 static ,方法二:把age改为全局变量,方法三:在int前面加上 __block ;方法一和方法二block里面修改age时都相当于直接拿到age的指针地址进行修改age,这时当然是可以修改的。方法三编译器会将 __block 变量包装成一个对象,也就是相当于在block里面创建了一个age对象有地址有内存,然后在block里改age就是改的自己创建的这个有地址有内存的age。方法一和方法二相当于把age改成了全局变量那么就会一直存在内存中,即使这个函数执行完了也不能及时释放,而在前面加上 __block 那么age也会在函数结束后及时释放,不会一直存在内存中。
		NSLog (@"age is %d", age);
		}
	}
	return 0;
}
## - 对象类型的auto变量、__block变量

1、当block在栈上时,对他们都不会产生强引用
2、当block拷贝到堆上时,都会通过copy函数来处理他们
(1)__block变量(假设变量名叫 a )
_Block_object_assign((void*)&dst->a, (void*)src->a, 8/*BLOCK_FIELD_IS_BYREF*/);
(2)对象类型的auto变量(假设变量名叫 p)
_Block_object_assign((void*)&dst->p, (void*)src->p, 3/*BLOCK_FIELD_IS_OBJECT*/);
3、当block从堆上移除时,都会通过dispose函数来释放它们
(1)__block变量(假设变量名叫 a )
_Block_object_dispose((void*)src->a, 8/*BLOCK_FIELD_IS_BYREF*/);
(2)对象类型的auto变量(假设变量名叫 p)
_Block_object_dispose((void*)src->p, 3/*BLOCK_FIELD_IS_OBJECT*/);
BLOCK_FIELD_IS_OBJECT:表示对象
BLOCK_FIELD_IS_BYREF:表示__block变量

- 被__block修饰的对象类型

1、当__block变量在栈上时,不会对指向的对象产生强引用
2、当__block变量被copy到堆时
(1)会调用__block变量内部的copy函数
(2)copy函数内部会调用_Block_object_assign函数
(3)_Block_object_assign函数会根据所指向对象的修饰符(__strong、__weak、__unsafe_unretained)作出相应操作,形成强引用(retain)或者弱引用(注意:这里仅限于ARC时会retain,MRC时不会retain)
3、如果__block变量从堆上移除
(1)会调用__block变量内部的dispose函数
(2)dispose函数内部会调用_Block_object_dispose函数
(3)_Block_object_dispose函数会自动释放指向的对象(release)

- 解决block循环引用问题 - ARC

方法一:用__weak、__unsafe_unretained 解决

__weak thpeof(self) weakSelf = self;
self.block = ^{
    printf("%p", weakSelf);
};

__unsafe_unretained id weakSelf = self;
self.block = ^{
    NSLog(@"%p", weakSelf);
}

方法二:用__block解决(必须要调用block)

__block id weakSelf = self;
self.block = ^{
    printf("%p", weakSelf);
    weakSelf = nil;
};
self.block();
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 这个错误通常是由于代码缩进不正确导致的。在 Python ,缩进是非常重要的,它决定了代码块的开始和结束。如果代码没有正确缩进,就会出现 IndentationError。 例如,在下面的示例代码,第 3 行的缩进不正确,会导致出现 IndentationError 错误: ``` def my_function(): print("Hello, World!") ``` 要解决这个错误,你需要将第 3 行的代码缩进修正,例如: ``` def my_function(): print("Hello, World!") ``` 这样就可以避免 IndentationError 错误。 ### 回答2: 当出现"IndentationError: expected an indented block"错误时,意味着在Python代码缺少了一个需要缩进的代码块。在Python,代码块是通过缩进来表示的,通常是使用四个空格或一个制表符。 这个错误通常是由于在代码的条件语句、循环语句或函数定义后没有正确缩进导致的。Python要求在这些语句或定义之后的下一行必须进行缩进,并在缩进块编写相关的代码。 例如,下面是一个导致IndentationError错误的示例代码: ``` if True: print("Hello, World!") ``` 在这个例子,缺少了对于if语句下一行的缩进,因此会引发错误。要解决这个错误,需要将缩进正确地应用到相应的代码块,如下所示: ``` if True: print("Hello, World!") ``` 在这个修正后的代码,print语句被正确地缩进了四个空格,以表示它处于if语句的代码块。 总之,"IndentationError: expected an indented block"错误是由于缺少需要缩进的代码块导致的。为了解决这个错误,我们需要在相关的条件语句、循环语句或函数定义后正确地缩进代码块。 ### 回答3: IndentationError: expected an indented block 是Python的语法错误之一,意味着代码缺少了一个需要缩进的代码块。 Python是通过缩进来表示代码块层次关系的,每个代码块都需要进行缩进。如果出现IndentationError错误,通常是由于缩进不正确所导致的。 解决这个错误的方法是在出现错误的代码行后面添加正确的缩进,使其属于上一行代码下面的一个代码块。 例如,下面的代码出现了IndentationError错误: ``` if True: print("Hello, world!") ``` 在这个例子,由于print("Hello, world!")没有正确缩进,所以会出现IndentationError错误。 要修复这个错误,我们需要在print语句前面添加4个空格的缩进,使其属于if语句的代码块: ``` if True: print("Hello, world!") ``` 修复后的代码就可以正确执行了。 总结起来,当出现了IndentationError: expected an indented block错误时,我们需要检查代码的缩进是否正确,确保每个代码块都有正确的缩进。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值