以前看到Block觉得也没什么,不就是类似函数的东西,这东西在C#里就是委托,在Java里就是块,有什么稀奇的。但看到一点进阶的内容后,发现这个东西确实有用。

所以做下总结。

一、块的基本用法

块的语法构成:

^[返回值类型](形参1,形参2,...) {

        //执行体

 }

在JS里,函数是可以做为变量的,OC的块也用变量接收,变量的声明语法:

//可以把形参名省略,只保留类型
返回值类型 (^块名) (形参1,形参2,...);

再来看几个例子就懂基本怎么用了:

int main(int argc , char * argv[])
{
@autoreleasepool{
// 定义不带参数、无返回值的块
void (^printString)(void) = ^(void)
{
NSLog(@"我正在开始学习Objective-C的块");
};
// 使用printString调用块
printString();
// 定义带参数、有返回值的块
double (^hypot)(double , double) =
^(double num1, double num2)
{
return sqrt(num1 * num1 + num2 * num2);
};
// 调用块,并输出块的返回值
NSLog(@"%g" , hypot(, ));
// 也可以先只定义块变量:定义带参数、无返回值的块
void (^print)(NSString*);
// 再将块赋给指定的块变量
print = ^(NSString* info)
{
NSLog(@"info参数为:%@" , info);
};
// 调用块
print(@"树狗狗");
}
}

还有一点要注意,块可以访问程序局部变量的值,但不能进行修改:

int main(int argc , char * argv[])
{
@autoreleasepool{
// 定义局部变量
int my = ;
void (^printVar)(void) = ^(void)
{
// 尝试对局部变量赋值,程序将会报错
// my = 30;
           // ①
// 访问局部变量的值是允许的
NSLog(@"%d" , my);
};
// 再次将my赋值为45
my = ;
// 调用块
printVar();
}
}

上在程序尝试修改局部变量,但会报错,而调用块前,把局部变量修改为45后再调用块,这个时候输出的却是:20,因为块定义时会把局部变量的值保存,而不是运行时去读取。

但这却是可以解决的,OC提供了一个_block关键字,用在定义局部变量时,让块里可以等到运行时访问,或者修改都可以。这样用:

int main(int argc , char * argv[])
{
@autoreleasepool{
// 定义__block修饰的局部变量
__block int my = ;
void (^printVar)(void) = ^(void)
{
// 运行时候访问、获取局部变量的值,此处输出45
NSLog(@"%d" , my);
// 尝试对__block局部变量赋值是允许的
my = ; // ①
// 此处输出30
NSLog(@"%d" , my);
};
// 再次将my赋值为45
my = ;
// 调用块
printVar();
// 由于块修改了__block局部变量的值,因此下面代码输出30
NSLog(@"块执行完后,my的值为:%d" , my);
}
}

既然可以完全访问,为什么不一开始就干脆去掉不能访问这条规则?难道仅仅是为了在运行时免去查找的过程么?搞不懂架构OC语言的人。

当然,如果块就这点用法的话,那它就没有什么必要存在了,在实际中,用的最多的是回调。

二、页面传值

要完成这样的一个功能:

在ViewController A中,点击按钮,push到ViewController B中,在B中的输入框输入值,返回到A中,在A中的Label上显示出来

第一种方法:协议代理。 就像Android里的Fragment传值那样。

首先定义一个协议:

//ViewController A要服从该协议,实现协议中的方法
@protocol TransportDelegate <NSObject>
- (void)setTextValue:(NSString *)text;
@end

ViewController A中代码:

//ViewControllerA.m 文件
@interface ViewController ()<TransportDelegate>
@property (strong, nonatomic) IBOutlet UILabel *label; @end
//点击Button进入下一个ViewCOntroller B页面
- (IBAction)nextBtnClicked:(id)sender
{
NextViewController *nextVC = [[NextViewController alloc] initWithNibName:@"NextViewController" bundle:nil];
  //相当于让下一个视力控制器持有自身的一个引用
nextVC.delegate = self;
[self.navigationController pushViewController:nextVC animated:YES];
} //实现协议TransportDelegate中的方法
#pragma mark - TransportDelegate method
- (void)setTextValue:(NSString *)text
{
//self.nextVCInfoLabel是显示NextViewController传递过来的值
self.label.text = tfText;
}

看到这,应该就可以猜到,ViewController B里,持有一个协议的引用,返回时,回调协议引用对象的方法:

@interface NextViewController : UIViewController
@property (nonatomic, assign) id<TransportDelegate> delegate;
@property (strong, nonatomic) IBOutlet TextField* textField;
@end

//NextViewController.m 文件
//返回前一个ViewController页面
- (IBAction)backBtnClicked:(id)sender {
if (self.delegate && [self.delegate respondsToSelector:@selector(setTextValue:)]) {
[self.delegate setTextValue:self.textField.text];
}
[self.navigationController popViewControllerAnimated:YES];
}

这就完成了页面间传值。总结来说就是,让B持有一个A的引用,在B中回调A中的方法,引用的桥梁是协议。用起来很麻烦,传个值而已还要定义个什么协议! 用Block就简单很多。

第二种方法:用Block

ViewController A中代码:

- (IBAction)btnClicked:(id)sender
{
NextViewController *nextVC = [[NextViewController alloc] initWithNibName:@"NextViewController" bundle:nil];
  //这里才给ViewController B的块变量赋值
nextVC.transportBlock = ^(NSString *text){
[self setLabelText:text];
};
[self.navigationController pushViewController:nextVC animated:YES];
}
#pragma mark - setLabeText method
- (void)setLabelText:(NSString *)text
{
self.label.text = text;
}

还是一样,看到这里,应该就可以猜到了,ViewController B里,直接调用块变量就可以:

//NextViewController.h 文件
@interface NextViewController : UIViewController
@property (nonatomic, copy) void (^transportBlock)(NSString *text);
@property (strong, nonatomic) IBOutlet TextField* textField;
@end
//NextViewContorller.m 文件
- (IBAction)backBtnClicked:(id)sender {
if (self.transportBlock) {
self.transportBlock(self.textField.text);
}
[self.navigationController popViewControllerAnimated:YES];
}

简单了许多,不用实现协议,虽然看起来也像反向代理.

iOS Block理解的更多相关文章

  1. iOS - Block底层解析

    Block是iOS开发中一种比较特殊的数据结构,它可以保存一段代码,在合适的地方再调用,具有语法简介.回调方便.编程思路清晰.执行效率高等优点,受到众多猿猿的喜爱.但是Block在使用过程中,如果对B ...

  2. # iOS Block的本质(三)

    iOS Block的本质(三) 上一篇文章iOS Block的本质(二)中已经介绍过block变量的捕获,本文继续探寻block的本质. 1. block对对象变量的捕获,ARC 环境 block一般 ...

  3. iOS Block的本质(二)

    iOS Block的本质(二) 1. 介绍引入block本质 通过上一篇文章Block的本质(一)已经基本对block的底层结构有了基本的认识,block的底层就是__main_block_impl_ ...

  4. iOS Block的本质(一)

    iOS Block的本质(一) 1.对block有一个基本的认识 block本质上也是一个oc对象,他内部也有一个isa指针.block是封装了函数调用以及函数调用环境的OC对象. 2.探寻block ...

  5. iOS Block界面反向传值

    在上篇博客 <iOS Block简介> 中,侧重解析了 iOS Block的概念等,本文将侧重于它们在开发中的应用. Block是iOS4.0+ 和Mac OS X 10.6+ 引进的对C ...

  6. iOS block从零开始

    iOS block从零开始 在iOS4.0之后,block横空出世,它本身封装了一段代码并将这段代码当做变量,通过block()的方式进行回调. block的结构 先来一段简单的代码看看: void ...

  7. iOS block 机制

    本文要将block的以下机制,并配合具体代码详细描述: block 与 外部变量 block 的存储域:栈块.堆块.全局块 定义 块与函数类似,只不过是直接定义在另一个函数里,和定义它的那个函数共享同 ...

  8. ios Block详细用法

    ios Block详细用法 ios4.0系统已开始支持block,在编程过程中,blocks被Obj-C看成是对象,它封装了一段代码,这段代码可以在任何时候执行.Blocks可以作为函数参数或者函数的 ...

  9. iOS --runtime理解

    iOS~runtime理解 Runtime是想要做好iOS开发,或者说是真正的深刻的掌握OC这门语言所必需理解的东西.最近在学习Runtime,有自己的一些心得,整理如下,一为 查阅方便二为 或许能给 ...

随机推荐

  1. 解决Mysql连接池被关闭 ,hibernate尝试连接不能连接的问题。 (默认mysql连接池可以访问的时间为8小时,如果超过8小时没有连接,mysql会自动关闭连接池。系统发布第二天访问链接关闭问题。

    解决Mysql连接池被关闭  ,hibernate尝试连接不能连接的问题. (默认MySQL连接池可以访问的时间为8小时,如果超过8小时没有连接,mysql会自动关闭连接池. 所以系统发布第二天访问会 ...

  2. 【转载】maven插件mybatis-generator自动生成 (1)

    http://blog.csdn.net/itlqi/article/details/49534447 1.新建一个maven项目在pom.xml添加如下: <plugins> <p ...

  3. tomcat 远程调试

    1.服务端查看cataline.sh 中的描述  cataline jpda start 开启服务端远程调试 远程调试端口JPDA_ADDRESS="8000" 2.本地代码参考  ...

  4. QT,静态变量要记得初始化

    //DbUtil.h #ifndef DBUTIL_H #define DBUTIL_H using namespace std; QString md5Encode(QString passwd); ...

  5. Chrome Extension 检查视图(无效)处理方法

    最近闲来无事,简单看了下Chrome扩展的开发,并且开发一个小小的翻译插件(TranslateBao)作为练手,开发细节不详述了,如果有新学习chrome extension开发的新人,可以参考源码, ...

  6. js == 与 === 的区别

    1.对于string,number等基础类型,==和===是有区别的 1)不同类型间比较,==之比较“转化成同一类型后的值”看“值”是否相等,===如果类型不同,其结果就是不等 2)同类型比较,直接进 ...

  7. phpcms 整合 discuz!

    第一步,进入discuz后台,点击UCenter菜单,然后点击应用管理,接着点击右侧的添加新应用按钮 然后填写应用相关信息: 1.应用类型选择“其他” 2.应该名称填写“phpcms” //此处可以自 ...

  8. ssh反向连接和简单实现

    转自:http://blog.chinaunix.net/uid-20109107-id-2954579.html SSH反向连接的使用 1.什么是反向连接?反向连接是指主机A(受控端)主动连接主机B ...

  9. nodejs学习

    转自于网络: ubuntu 下面安装 vim 的问题 1.输入vim时,显示: 程序"vim"已包含在以下软件包中: * vim * vim-gnome * vim-tiny * ...

  10. CSS3属性box-sizing

    1.box-sizing属性是CSS3的属性,有3个值:border-box.content-box.inherit. 2.默认是content-box,就是我们知道的width.padding.bo ...