iOS之block浅谈

前言

ios4.0系统已开始支持block,在编程过程中,block被Obj-C看成是对象,它封装了一段代码,这段代码可以在任何时候执行。block可以作为函数参数或者函数的返回值,而其本身又可以带输入参数或返回值。它和传统的函数指针很类似,但是有区别:block是inline的,并且它对局部变量是只读的。

block和函数的相似性:(1)可以保存代码(2)有返回值(3)有形参(4)调用方式一样。

block的使用

1、block的定义

// 声明和实现写在一起,就像变量的声明实现 int a = 10;

int(^aBlock)(int,int) = ^(intnum1,intnum2) {

returnnum1 * num2;

};

// 声明和实现分开,就像变量先声明后实现 int a;a = 10;

int(^cBlock)(int,int);

cBlock = ^(intnum1,intnum2)

{

returnnum1 * num2;

};

其中,定义了一个名字为aBlock的blocks对象,并携带了相关信息:

1、aBlock 有两个形式参数,分别为int类型;

2、aBlock 的返回值为int 类型;

3、等式右边就是blocks的具体实现;

4、^ 带边blocks声明和实现的标示(关键字);

当然,你可以定义其他形式的block。e.g:无返回值,无形式参数等;

void(^bBlock)() = ^()

{

inta =10;

printf(num = %d,a);

};

2、blocks 访问权限

blocks可以访问局部变量,但是不能修改。

inta =10;

int(^dBlock)(int) = ^(intnum)

{

a++;//not work!

returnnum * a;

};

此处不能修改的原因是在编译期间确定的,编译器编译的时候把a的值复制到block作为一个新变量(假设是a‘ = 10),此时a‘和a是没有关系的。

这个地方就是函数中的值传递。如果要修改就要加关键字:__block或者static

__blockinta =7;

int(^dBlock)(int) = ^(intnum)

{

a++;// work!

returnnum * a;

};

3、block的调用

block调用就像调用函数一样。e.g:

1intc = aBlock(10,10);

bBlock();

4、block 应用

假设我们熟悉代理递值的话,对代理我们可能又爱有恨!我们先建立模型A页面 push

B页面,如果把A页面的值传递到B页面,属性和单例传值可以搞定!但是如果Pop过程中把B页面的值传递到A页面,那就可以用单例或者代理了!说到代理,

我们要先声明协议,创建代理,很是麻烦。常常我们传递一个数值需要在两个页面间写很多代码,这些代码改变页面的整体顺序,可读性也打了折扣。所以,此

时,block是一种优化方案!

5、 block的内存管理

block本身是像对象一样可以retain,和release。但是,block在创建的时候,它的内存是分配在栈(stack)上,而不是在堆(heap)上。他本身的作于域是属于创建时候的作用域,一旦在创建时候的作用域外面调用block将导致程序崩溃。比如下面的例子。 我在view did load中创建了一个block:

- (void)viewDidLoad

{

[superviewDidLoad];

int number = 1;

_block = ^(){

NSLog(@number %d, number);

};

}

并且在一个按钮的事件中调用了这个block:

- (IBAction)testDidClick:(id)sender {

_block();

}

此时我按了按钮之后就会导致程序崩溃,解决这个问题的方法就是在创建完block的时候需要调用copy的方法。copy会把block从栈上移动到堆上,那么就可以在其他地方使用这个block了~ 修改代码如下:

_block = ^(){

NSLog(@number %d, number);

};

_block = [_blockcopy];

同理,特别需要注意的地方就是在把block放到集合类当中去的时候,如果直接把生成的block放入到集合类中,是无法在其他地方使用block,必须要对block进行copy。不过代码看上去相对奇怪一些:

[array addObject:[[^{

NSLog(@hello!);

} copy] autorelease]];

6、循环引用

对于非ARC下, 为了防止循环引用, 我们使用__block来修饰在Block中使用的对象:

对于ARC下, 为了防止循环引用, 我们使用__weak来修饰在Block中使用的对象。原理就是:ARC中,Block中如果引用了__strong修饰符的自动变量,则相当于Block对该变量的引用计数+1。

这一点其实是在第一点的一个小的衍生。当在block内部使用成员变量的时候,比如

@interface ViewController : UIViewController

{

NSString *_string;

}

@end

在block创建中:

_block = ^(){

NSLog(@string %@, _string);

};

这里的_string相当于是self->_string;那么block是会对内部的对象进行一次retain。也就是说,self会被retain一次。当self释放的时候,需要block释放后才会对self进行释放,但是block的释放又需要等self的dealloc中才会释放。如此一来变形成了循环引用,导致内存泄露。

修改方案是新建一个__block scope的局部变量,并把self赋值给它,而在block内部则使用这个局部变量来进行取值。因为__block标记的变量是不会被自动retain的。

__block ViewController *controller = self;

_block = ^(){

NSLog(@string %@, controller->_string);

};

博主浏览了很多博客,总结了一下,block实际上是(底层c++): 指向结构体的指针,底层会创建一个结构体,实现构造方法,来接参数,编译器会将block的内部代码生成对应的函数。

block实战:用block进行页面间传值

使用Block的地方很多,其中传值只是其中的一小部分,下面介绍Block在两个界面之间的传值:

先说一下思想:

首先,创建两个视图控制器,在第一个视图控制器中创建一个UILabel和一个UIButton,其中UILabel是为了显示第二个视图控制器传过来的字符串,UIButton是为了push到第二个界面。

第二个界面的只有一个UITextField,是为了输入文字,当输入文字,并且返回第一个界面的时候,当第二个视图将要消失的时候,就将第二个界面上TextFiled中的文字传给第一个界面,并且显示在UILabel上。

其实核心代码就几行代码:

下面是主要代码:(因为我是用storyBoard创建的工程,所以上面的属性和相应的方法,是使用系统生成的outlet)

一、在第二个视图控制器的.h文件中定义声明Block属性

typedef void(^ReturnTextBlock)(NSString *showText);

@interface TextFieldViewController : UIViewController

@property(nonatomic, copy) ReturnTextBlock returnTextBlock;

- (void)returnText:(ReturnTextBlock)block;

@end

第一行代码是为要声明的Block重新定义了一个名字

ReturnTextBlock

这样,下面在使用的时候就会很方便。

第三行是定义的一个Block属性

第四行是一个在第一个界面传进来一个Block语句块的函数,不用也可以,不过加上会减少代码的书写量

二、实现第二个视图控制器的方法

- (void)returnText:(ReturnTextBlock)block {

self.returnTextBlock = block;

}

- (void)viewWillDisappear:(BOOL)animated {

if(self.returnTextBlock != nil) {

self.returnTextBlock(self.inputTF.text);

}

}

其中inputTF是视图中的UITextField。

第一个方法就是定义的那个方法,把传进来的Block语句块保存到本类的实例变量returnTextBlock(.h中定义的属性)中,然后寻找一个时机调用,而这个时机就是上面说到的,当视图将要消失的时候,需要重写:

- (void)viewWillDisappear:(BOOL)animated;

方法。

三、在第一个视图中获得第二个视图控制器,并且用第二个视图控制器来调用定义的属性

如下方法中书写:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender

{

// Get the new view controller using [segue destinationViewController].

// Pass the selected object to the new view controller.

TextFieldViewController *tfVC = segue.destinationViewController;

[tfVC returnText:^(NSString *showText) {

self.showLabel.text = showText;

}];

}

揭开block神秘面纱

假设A有一个任务,是去仓库取一张A4纸放到会议室,然后在纸上写一份策划书。取纸又要经过仓库管理员,于是A通知仓库管理员来张纸过来。由于管理员是个老

头动作很慢,另外A还有其他工作,如果一直等待管理员就太浪费时间了,合理的做法是让仓库管理员进行取纸这项工作,A在通知管理员后就继续自己的工作。A

不知道仓库管理员什么时候能完成取纸,也就不知道什么时候可以在纸上写策划书。这时block机制就派上用场了,使用这种机制,可以让A在通知仓库管理员

取纸的同时,告诉仓库管理员将纸放到编号XX会议室,并安排好将要在纸上写的策划内容,当管理员把纸拿来后,可能过一会就会有个助理将策划内容写到纸上。

我们将这个故事对应到代码上:

#pragma mark - 第三方登录

- (void)btnLoginWeiboClicked:(id)sender {

[_waitCirclestartAnimating];

[[HSLoginClasscreateInstance]loginWithPlatformType:ShareTypeSinaWeibowithBlock:^(BOOLsuccess,idmessage) {

if(success) {

//跳出登录页面

[selfdismissViewControllerAnimated:YEScompletion:^{}];

[_waitCirclestopAnimating];

NSLog(@"新浪微博 %@", message);

}else{

}

}];

//test statistics

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{

NSDate* date = [NSDatedate];

NSTimeInterval nowTime = [datetimeIntervalSince1970];

NSString* netStatus = (NSString*)[[NSUserDefaultsstandardUserDefaults]objectForKey:NETSTATUS];

[[HSStatisticsModulestatisticsModule]makeSession:nowTime :OPER_IN :@"noid"];

[[HSStatisticsModulestatisticsModule]upLoadData:netStatus :[NSStringstringWithFormat:@"%f",nowTime]];

});

}

请看这段代码,整个方法是A要做的工作,startAnimating/loginWithPlatformType/dispatch_async分别是A要做的三个任务,由于loginWithPlatformType需要一段时间才能完成,并且loginWithPlatformType完成后要根据结果做相应处理,所以我们对loginWithPlatformType进行异步处理。block代码段是loginWithPlatformType得到结果后要做的操作H,这里的block写法就表示,我们先将操作H安排好,然后继续其他工作,当loginWithPlatformType执行ok后自会有人(可能是那个助理)去执行操作H。

iOS面试之block

1 什么是block

对于闭包(block),

有很多定义,其中闭包就是能够读取其它函数内部变量的函数,这个定义即接近本质又较好理解。对于刚接触Block的同学,会觉得有些绕,因为我们习惯写这

样的程序main(){ funA();} funA(){funB();} funB(){.....};

就是函数main调用函数A,函数A调用函数B...

函数们依次顺序执行,但现实中不全是这样的,例如项目经理M,手下有3个程序员A、B、C,当他给程序员A安排实现功能F1时,他并不等着A完成之后,再

去安排B去实现F2,而是安排给A功能F1,B功能F2,C功能F3,然后可能去写技术文档,而当A遇到问题时,他会来找项目经理M,当B做完时,会通知

M,这就是一个异步执行的例子。在这种情形下,Block便可大显身手,因为在项目经理M,给A安排工作时,同时会告诉A若果遇到困难,如何能找到他报告

问题(例如打他手机号),这就是项目经理M给A的一个回调接口,要回掉的操作,比如接到电话,百度查询后,返回网页内容给A,这就是一个Block,在M

交待工作时,已经定义好,并且取得了F1的任务号(局部变量),却是在当A遇到问题时,才调用执行,跨函数在项目经理M查询百度,获得结果后回调该

block。

2 block 实现原理

Objective-C是对C语言的扩展,block的实现是基于指针和函数指针。

从计算语言的发展,最早的goto,高级语言的指针,到面向对象语言的block,从机器的思维,一步步接近人的思维,以方便开发人员更为高效、直接的描述出现实的逻辑(需求)。

下面是两篇很好的介绍block实现的博文

iOS中block实现的探究

谈Objective-C Block的实现

3 block的使用

使用实例

cocoaTouch框架下动画效果的Block的调用

使用typed声明block

typedef void(^didFinishBlock) (NSObject *ob);

这就声明了一个didFinishBlock类型的block,

然后便可用

@property (nonatomic,copy) didFinishBlock  finishBlock;

声明一个block对象,注意对象属性设置为copy,接到block 参数时,便会自动复制一份。

__block是一种特殊类型,

使用该关键字声明的局部变量,可以被block所改变,并且其在原函数中的值会被改变。

4 常见系列面试题

面试时,面试官会先问一些,是否了解block,是否使用过block,这些问题相当于开场白,往往是下面一系列问题的开始,所以一定要如实根据自己的情况回答。

1 使用block和使用delegate完成委托模式有什么优点?

首先要了解什么是委托模式,委托模式在iOS中大量应用,其在设计模式中是适配器模式中的对象适配器,Objective-C中使用id类型指向一切对象,使委托模式在iOS中的实现更为方便。了解委托模式的细节:

iOS设计模式----委托模式

使用block实现委托模式,其优点是回调的block代码块定义在委托对象函数内部,使代码更为紧凑;

适配对象不再需要实现具体某个protocol,代码更为简洁。

2 多线程与block

GCD与Block

使用 dispatch_async系列方法,可以以指定的方式执行block

GCD编程实例

dispatch_async的完整定义

void dispatch_async(

dispatch_queue_t queue,

dispatch_block_t block);

功能:在指定的队列里提交一个异步执行的block,不阻塞当前线程

通过queue来控制block执行的线程。主线程执行前文定义的 finishBlock对象

dispatch_async(dispatch_get_main_queue(),^(void){finishBlock();});

参考博客:

http://blog.csdn.net/xunyn/article/details/11658261

http://www.2cto.com/kf/201504/388349.html

博主的微博、CocoaChina博客、简书同步更新,欢迎关注:

新浪微博:http://weibo.com/p/1005052308506177/home?from=page_100505_profile&wvr=6&mod=data&is_all=1#place

简书:http://www.jianshu.com/users/63baf9271d14/latest_articles

CocoaChina:http://blog.cocoachina.com/477998

时间: 2024-10-14 12:59:36

iOS之block浅谈的相关文章

iOS开发>学无止境 - 浅谈MVVM的架构设计与团队协作

李刚按:本文是青玉伏案写的一篇文章.相信大家对MVC耳熟能详,MVVM可能听说的相对少一些,这一篇文章将会想你阐述MVVM设计,还有团队协作的经验分享.如果你也觉得不错,就分享一下吧! demo:https://github.com/lizelu/MVVM 今天写这篇文章是想达到抛砖引玉的作用,想与大家交流一下思想,相互学习,博文中有不足之处还望大家批评指正.本篇文章的内容沿袭以往博客的风格,也是以干货为主,偶尔扯扯咸蛋(哈哈~不好好工作又开始发表博客啦~). 由 于本人项目经验有限,关于架构设

iOS开发之浅谈MVVM的架构设计与团队协作

今天写这篇博客是想达到抛砖引玉的作用,想与大家交流一下思想,相互学习,博文中有不足之处还望大家批评指正.本篇博客的内容沿袭以往博客的风格,也是以干货为主,偶尔扯扯咸蛋(哈哈~不好好工作又开始发表博客啦~). 由于本人项目经验有限,关于架构设计方面的东西理解有限,我个人对MVVM的理解主要是借鉴于之前的用过的MVC的Web框架~在学校的时候用过ThinkPHP框架,和SSH框架,都是MVC的架构模式,今天MVVM与传统的MVC可谓是极为相似,也可以说是兄弟关系,也就是一家人了. 说道架构设计和团队

iOS应用架构浅谈

缘由 从事iOS工作一年多了,主要从事QQ钱包SDK开发和财付通app维护,随着对业务的慢慢熟悉,最近在思考这两款应用架构设计的思想,刚好昨天在微信里看了一篇iOS大牛对终端应用架构的分享,乘热打铁,下面浅谈下我对ios应用架构设计的理解,写的不好或不对的地方,欢迎大家拍砖,我们一起来探讨. 假如问你一个iOS or Android app的架构,你会从哪些方面来说呢? 不要急着给出你的答案,可以先在你的脑子里思考3分钟,再看下面我要讲的内容. 其实对于iOS客户端应用的架构来说,复杂度不亚于服

iOS之RunTime浅谈

首先说一下什么是runtime:RunTime简称运行时.就是系统在运行的时候的一些机制,其中最主要的是消息机制.对于C语言,函数的调用 在编译的时候会决定调用哪个函数( C语言的函数调用请看这里 ).编译完成之后直接顺序执行,无任何二义性.OC的函数调用成为消息发送.属于动态调用过程.在编译的时候并不能决定真正调用哪个函数(事实证明,在编 译阶段,OC可以调用任何函数,即使这个函数并未实现,只要申明过就不会报错.而C语言在编译阶段就会报错).只有在真正运行的时候才会根据函数的名称找 到对应的函

iOS多线程编程——浅谈GCD

GCD对于iOS开发者来说肯定不陌生,他和NSThread,NSOperation一起作为iOS开发中主要的三种多线程实现方法,而GCD是最最底层的,所以对于作为一个iOSer,GCD是必须掌握的. 我通过对于以下两篇文章的阅读,基本上掌握了GCD的基本使用方法.所以首先感谢两位作者. GCD 深入理解:第一部分 iOS多线程开发--GCD的使用与多线程开发浅析(二) 一.基本概念 对于新手来说,最常见同时最容易搞混的的莫过于GCD中的一些基本概念了. 并行与并发(Parallelism &&am

ios开发新手浅谈强大的runtime机制

runtime机制,实际上是一套底层的C语言代码,里面提供了很多的C数据类型和一些功能强大的C语言函数.我们所写的OC代码,在底层都是基于runtime来实现的.所以我们可以说OC实际就是披着面向对象外衣的C语言,因为在运行时,OC代码会编译成C/C++ 来运行.runtime中有很多的C函数,有着很强大的功能,比如 : 1. 能动态类的增删改 成员变量,方法 2.IOS Swizzle 能底层动态的交换两个方法(类方法和对象方法)的实现 IOS swizzle的具体做法: 1.在分类的load

iOS推送浅谈

推送这个功能小伙伴们肯定是经常遇到,对于有些app的推送频次更是感觉够了.但是作为一枚合格的iOS开发攻城狮,这项重要的必备技能还是必须得掌握.下面就个人的经验说说怎么添加推送(这里用的腾讯信鸽平台). 一.准备推送证书和描述文件 创建证书和描述文件的方法请参考我的博客<iOS真机调试流程>,但具体有点点不同 创建app id的时候,在第二个页面记得勾选下图中红色框框标明的选项,因为咱们要创建的是推送证书 创建证书的时候,勾选如下图选项 利用终端执行如下命令 “openssl pkcs12 -

iOS之多线程浅谈

1)并发和并行的区别 在软件开发中不可避免的会遇到多线程的问题,在iOS客户端开发(或者.NET的winform或者wpf这样的cs程序)中就更不可避免的会用到多线程,在bs类型的web项目中要考虑一个并发问题,而在这里我们来说一下多线程的并行问题. 首先了解并发和并行的区别: 并发的实质是一个物理CPU(也可以多个物理CPU) 在若干道程序之间多路复用,并发性是对有限物理资源强制行使多用户共享以提高效率.但同一个时刻只能有一个用户使用资源,通过时间的间隔来实现一个逻辑上的并行效果. 并行性指两

iOS 应用架构浅谈

当我们讨论客户端应用架构的时候,我们在讨论什么? 其实市面上大部分应用不外乎就是颠过来倒过去地做以下这些事情: 简单来说就是调API,展示页面,然后跳转到别的地方再调API,再展示页面. App确实就是主要做这些事情,但是支撑这些事情的基础,就是做架构要考虑的事情. 调用网络API 页面展示 数据的本地持久化 动态部署方案 上面这四大点,稍微细说一下就是: 如何让业务开发工程师方便安全地调用网络API?然后尽可能保证用户在各种网络环境下都能有良好的体验? 页面如何组织,才能尽可能降低业务方代码的