对于block之前想多了,从理解方向上出现问题,一直以为是个坎,闲来无事研究半天,感觉有点思路。虽然通了些,但对于深层次理解及灵活运用必然不到位,所以暂定block第一步。并且block多种语法也记不住,写此笔记,便于日后查看。
文章结构网络借鉴,block的几种用法。
(1).本地变量
int (^sumBlock)(int ,int) = ^(int a,int b){ return a+b; }
(2).成员属性
@property(nonatomic,copy) void(^wwBlock)(NSString *);
(3).方法参数
-(void)returntextWith:(void(^)(NSString *dd))ssblock;
(4).typedefin
typedef int (^sumBlock)(int a,int b);
sumBlock myblock = ^int (int a,int b){ }
**typedefin 只是讲block起别名,定义成sumblock、block属性用copy**
(1).用作本地变量
NSString* (^nameBlock)(NSString *,NSString *) = ^(NSString *first,NSString *last){
NSString *name = [NSString stringWithFormat:@"%@ %@",first,last];
return name;
};
NSLog(@"%@",nameBlock(@"zhao",@"si"));
本地变量与 int a = 7;一样
* block可以访问局部变量,但是不能修改,否则会编译报错.
如果要在block内部修改局部变量,则需要使用__block来修饰该局部变量,如下,
__block NSString *lastName = @"wang";
* 当我们无法理解block如何产生各种回调时以及原理时,不妨冷静头脑看一下block最基本的用法:
block名言: ** * 要想执行block大括号内部的代码(即回调代码),只要在你想的地方敲出block名字,填要传的参数即可,大括号内的回调代码就可以用这些参数处理问题***
如上文我们想知道@"zhao"与@"si"的组合名字是什么,我们在某处调用block并填写参数:nameBlock(@"zhao",@"si"),括号内执行:NSString *name = [NSString stringWithFormat:@"%@ %@",first,last];
至此 貌似block的功能也可以用函数或一个返回合并后的字符串解决,但细想,block可以传多个参数(个人认为block的最大优势,暂时的理解)。
(2).用作成员属性
声名方法:@property(notomic ,copy)void (^myBlock)(NSString *);
block 用作本地变量的经典作用就是界面B对界面A的值得回传。
栗子:有界面A和界面B,在界面B中取得的值,需要回传到界面A。
思维分析:A界面要想拿到B界面的值,以block思维,必然是A有block代码块,B在想调用的时候调用并传参,A得到参数(即B穿给A的值)。
实现方法:
1.在B控制器定义一个block属性
@property(nonatomic,copy) void(^wwBlock)(NSString *);
2.在B.h中声名一个带有Block的方法,写法如下:
声名:
-(void)returntextWith:(void(^)(NSString *dd))ssblock;
这个方法是为了在跳转到B界面时把A中的block传给B,并且B保存到step 1中定义的属性。(稍有点绕,作用且看)
实现:
-(void)returntextWith:(void(^)(NSString *dd))ssblock{
self.wwBlock = ssblock;
}
3.B界面调用自己的block,也就是A传来的Block,保存在属性中,指针地址相同。
-(void)btClink{
if (self.wwBlock != nil) {
self.wwBlock(@"你好");
}
[self.navigationController popViewControllerAnimated:YES];
}
点击按钮,调用wwBlock,将B中的“你好”,作为参数。这个block的代码块在A界面,所以block会去A界面执行回调。
0.A界面代码
B_ViewController *Bvc = [[B_ViewController alloc]init];
[Bvc returntextWith:^(NSString *dd) { NSLog(@"%@",dd); }];
[self.navigationController pushViewController:VC animated:YES];
A 界面在push到B界面时,调用B界面的return方法,将NSLog回调代码块作为方法参数传给B,(B保存到属性),当B调用block时,执行代码块,打印dd (传来的值)。
?(一直纠结打印应该再B界面而非A界面,但运行代码发现确实回到A界面调用Log,或许是因为block是在A界面定义的,B界面只是得到了同一指针,结合block用作函数参数又感觉想多了,就是先后问题)
*熟练使用时,应先写A的代码,但暂时还是先写B,再写A。
*return方法:block作为函数参数是下段内容
(3).用作方法参数
当我们一根筋的理解好“block名言”时,block作为函数参数也就不必费事了。这个block就是函数的参数而已,只不过写法奇怪。而什么时候调用,或者是否调用,完全由我们控制。基本做法是,先执行方法,在方法中调用block,调用函数的地方会执行block。
Manger控制器中处理名字的方法,带有block参数,Manger.h代码:
-(void)mergeNamebByFisrt:(NSString )firstName last:(NSString )lastName responBlock:(void(^)(bool response,NSString *Name,NSInteger nameLength))myBlock;
Manger.m代码:
-(void)mergeNamebByFisrt:(NSString )firstName last:(NSString )lastName responBlock:(void(^)(bool response,NSString *Name,NSInteger nameLength))myBlock{
//处理方法内部任务
NSString *name = [NSString stringWithFormat:@"%@%@",firstName,lastName];
bool isContain = [name containsString:@"三"];
NSInteger namelen = name.length;
//调用block,根据此方法的处理结果,返回参数。
myBlock(isContain,name,namelen);
}
在控制器XX中调用此方法:
[MangerVC mergeNamebByFisrt:@"张" last:@"三" responBlock:^(bool response, NSString *Name, NSInteger nameLength) {
NSLog(@"名字是:%@ 名字占几个字符:%ld",Name,(long)nameLength);
if (response) {
NSLog(@" 名字包含“三”字 ");
}
}];
可以看到,程序调用方法时与以前一样,执行方法内部逻辑,只是执行完成后,我们可以调用block,这时XX控制器中调用时的block回调Log方法才会执行。
所以这种作为参数的block常常用于多线程处理网络请求,处理完成后block产生回调,更新UI或MBProgress "-处理完成-";
(4).用typedef 重新定义block格式
这只是用typedef 重新定义block而已,算是一个小技巧吧。
typedef int (^sumBlock)(int a,int b);
a. @property(notomic,copy)sumBlock ssblock;
b. sumBlock yyblock = ^int (int a,int b){return a+b;} ;
。。。。。