block小结
定义:
1 Block是C语言的
2 Block是一个数据类型
3 是一个提前准备好的代码,在需要的时候执行
/**
Block是C语言的
Block是一个数据类型
是一个提前准备好的代码,在需要的时候执行
*/
void demoBlock1();
void demoBlock2();
void demoBlock3();
int main(int argc, const char * argv[]) {
@autoreleasepool {
demoBlock3();
}
return 0;
}
void demoBlock3() {
// 指针记录的是地址
NSMutableString *strM = [NSMutableString stringWithString:@"zhangsan"];
NSLog(@"定义前 %p %p", strM, &strM);
void (^myBlock)() = ^ {
// 修改strM指针指向的内容
[strM setString:@"lisi"];
NSLog(@"inblock %p %p", strM, &strM);
// 这句代码是修改strM指针指向的地址
// strM = [NSMutableString stringWithString:@"wangwu"];
};
NSLog(@"定义后 %p %p", strM, &strM);
myBlock();
NSLog(@"%@", strM);
}
void demoBlock2() {
// 使用 __block,说明不在关心x数值的具体变化
__block int x = 10;
NSLog(@"定义前 %p", &x); // 栈区
// 如果要在block中,修改外部变量的数值,需要使用 __block 修饰符号
// 定义block时,如果引用了外部使用__block的变量,block定义之后,外部变量的指针地址同样会变成堆区的地址
void (^myBlock)() = ^ {
x = 80;
NSLog(@"in block %p", &x); // 堆区
};
NSLog(@"定义后 %p", &x); // 堆区
myBlock();
NSLog(@"%d", x);
}
</pre><pre code_snippet_id="1656895" snippet_file_name="blog_20160421_3_7967570" name="code" class="objc">void demoBlock1() {
int x = 10;
NSLog(@"定义前 %p", &x); // 栈区
// 提问:输出是多少?
// 在定义block的时候,如果引用了外部变量,会对外部变量做一个copy,记录住定义block时变量的数值
// 如果后续再修改x的值,不会影响block内部的数值变化!
// 在默认情况下,不允许block内部修改外部变量的数值!因为会破坏代码的可读性,不易于维护!
void(^myBlock)() = ^ {
// x = 80;
NSLog(@"%d", x);
NSLog(@"in block %p", &x); // 堆中的地址
};
NSLog(@"定义后 %p", &x); // 栈区
x = 20;
myBlock();
}
// block的定义
void demo() {
// block定义的速记符号
// inlineblock,能够快速敲出一个block的基本结构
// 提示:block的定义必须要过关!
// 如果记不住,可以用inlineblock辅助记忆,不要依赖inlneblock
// 定义block
/**
定义时,把block当成数据类型
特点:
1. 类型比函数定义多了一个 ^
2. 设置数值,有一个 ^,内容是 {} 括起的一段代码
最简单的定义方式
void (^myBlock)() = ^ { // 代码实现; }
*/
void (^myBlock)() = ^ {
NSLog(@"hello");
};
// 执行时,把block当成函数
myBlock();
// 定义带参数的block
// 格式:void (^block名称)(参数列表) = ^ (参数列表) { // 代码实现; }
void (^sumBlock)(int, int) = ^ (int x, int y) {
NSLog(@"%d", x + y);
};
sumBlock(10, 20);
// 定义带返回值的block
// 格式:返回类型 (^block名称)(参数列表) = ^ 返回类型 (参数列表) { // 代码实现; }
int (^sumBlock2)(int, int) = ^ int (int a, int b) {
return a + b;
};
NSLog(@"%d", sumBlock2(4, 8));
}
// 如果要将block当作返回值,需要先单独定义一下block的类型
// 速记符号:typedefBlock
typedef void(^workBlock)();
使用block进行排序,效率非常高,以后替换掉for循环
// 1. 从iOS4开始,苹果封装了一系列块代码简化操作,提高效率
// 1> 使用块代码遍历,效率比for in要高
// 2> 把循环所需要的所有素材都以参数的形式提供了,可以直接使用
[array enumerateObjectsUsingBlock:^(NSNumber *num, NSUInteger idx, BOOL *stop) {
NSLog(@"%@", num);
if (idx == 3) {
*stop = YES;
}
}];
排序(效率比正常排还要高)
NSArray *result = [array sortedArrayUsingComparator:^NSComparisonResult(NSNumber *num1, NSNumber *num2) {
// compare 可以比较NSString,NSDate,NSNumber...
// 升序
return [num1 compare:num2];
// 降序
return [num2 compare:num1];
// 乱序,随机的顺序=》一会升序,一会降序
int seed = arc4random_uniform(2);
if (seed == 1) {
// 升序
return [num1 compare:num2];
} else {
return [num2 compare:num1];
}
}];
注意点:
一. block
的反向传值
1. 调用方:准备块代码
跟 " 代理 " 来对比 - 类似于协议方法的实现
不同点:块代码都在一起,并没有单独的实现一个方法
2. 被调用方:执行块代码
1> 要执行的代码:在 .h 中定义一个块代码的属性,又被称作 “ 回调方法 ”
2> 在需要的时候执行块代码!
1. 调用方:准备块代码
跟 " 代理 " 来对比 - 类似于协议方法的实现
不同点:块代码都在一起,并没有单独的实现一个方法
2. 被调用方:执行块代码
1> 要执行的代码:在 .h 中定义一个块代码的属性,又被称作 “ 回调方法 ”
2> 在需要的时候执行块代码!
- 1 定义一个块代码的属性,block属性需要用copy
@property
(
nonatomic
,
copy
)
void
(^completion)(
NSString
*text);
- 2 给目标视图控制器传值(准备执行的块代码)
//
目标视图控制器
CZEditViewController
*vc = segue.
destinationViewController
;
vc.
completion
= ^ (
NSString
*str) {
self . nameLabel . text = str;
self . nameLabel . text = str;
};
- 3 在执行之前,先判断块代码属性是否有内容
if
(
self
.
completion
) {
self . completion ( self . nameText . text );
self . completion ( self . nameText . text );
}
block陷阱
block
的陷阱-有可能会出现循环引用
解决办法:
1. 要对内存对象之间的引用关系要清楚
技巧:
1. 在 block 中碰到 self ,要格外小心, “ 有可能 ” 会出现循环引用,通常最好思考一下
2. 利用 dealloc 协助判断!如果不能被正常释放就说明有循环引用!
解决办法:
1. 要对内存对象之间的引用关系要清楚
技巧:
1. 在 block 中碰到 self ,要格外小心, “ 有可能 ” 会出现循环引用,通常最好思考一下
2. 利用 dealloc 协助判断!如果不能被正常释放就说明有循环引用!
*** block
在反向传值上有什么特点?
-简单
-所有代码都在一起,便于阅读,便于维护
*** block & delegate 如何选择?
-如果回调方法比较少, 1 ~ 2 ,最好不要超过 3 个,这个时候使用 block 比较合适
-如果回调方法太多,会让代码显得臃肿,反而不好维护
-如果回调方法非常多,同时又不用每一个方法都必须实现,这个时候用 delegate 会比较方便!
-简单
-所有代码都在一起,便于阅读,便于维护
*** block & delegate 如何选择?
-如果回调方法比较少, 1 ~ 2 ,最好不要超过 3 个,这个时候使用 block 比较合适
-如果回调方法太多,会让代码显得臃肿,反而不好维护
-如果回调方法非常多,同时又不用每一个方法都必须实现,这个时候用 delegate 会比较方便!