1 什么是block

iOS SDK 4.0开始,Apple引入了block这一特性。字面上说,block就是一个代码块,但是它的神奇之处在于在内联(inline)执行的时候(这和C++很像)还可以传递参数。同时block本身也可以被作为参数在方法和函数间传递,这就给予了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。

block是一个特殊的OC对象, 它建立在栈上, 而不是堆上, 这么做一个是为性能考虑,还有就是方便访问局部变量.
默认情况下block使用到的局部变量都会被复制,而不是保留.
所以它无法改变局部变量的值.
如果在变量面前加上__block, 那么编译器回去不会复制变量, 而是去找变量的地址, 通过地址来访问变量, 实际上就是直接操作变量.
另外块是在栈上分配的, 所以一旦离开作用域, 就会释放, 因此如果你要把快用在别的地方, 必须要复制一份.
所以在属性定义一个快的时候需要使用copy:  @property (nonatomic, copy) void (^onTextEntered)(NSString *enteredText);
块是不能保留的, retain对块没有意义.
 
2 block 实现原理
Objective-C是对C语言的扩展,block的实现是基于指针和函数指针。
从计算语言的发展,最早的goto,高级语言的指针,到面向对象语言的block,从机器的思维,一步步接近人的思维,以方便开发人员更为高效、直接的描述出现实的逻辑(需求)。
 
3 block的使用
使用实例

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

动画效果是IOS界面重要的特色之一,其中CAAnimation是所有动画对象的抽象父类,作为新人,使用较多的是UIView下的动画方法(类方法)。使用UIView下的动画,有下面几个方法。

方法一:设置beginAnimations

其中memberView为需要添加的子视图的视图,mivc.view为子视图,在使用的时候,需要将这两个地方替换

需要注意的是,一定要使用[UIView commitAnimations];动画才会生效

通过[UIView setAnimationDuration:1]; 设置持续时间。

方法二:

在IOS4.0后,我们有了新的方法,+ (void)transitionWithView:(UIView *)view duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion,依然是UIView的类方法,但使用到了Block对象,Block对象是一组指令,可以传递(像变量一样),可以把它想像成C语言的函数指针。

[UIView transitionWithView:self.view
duration:0.2
options:UIViewAnimationOptionTransitionFlipFromLeft
animations:^{ [self.view addSubview:yellowView.view]; }
completion:NULL];

B:

使用typed声明block
typedef void(^didFinishBlock) (NSObject *ob);
这就声明了一个didFinishBlock类型的block,
然后便可用
@property (nonatomic,copy) didFinishBlock  finishBlock;
声明一个block对象,注意对象属性设置为copy,接到block 参数时,便会自动复制一份。 
__block是一种特殊类型,
使用该关键字声明的局部变量,可以被block所改变,并且其在原函数中的值会被改变。

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

block不同其它变量的原因在于它不是一个单一变量, 而是一个方法,

我们要传递的是一个代码块,并且这个代码块可以存在参数,

这个参数并不是在定义block的时候就赋予值, 而是我们在实际运行block的时候才赋予值.

因此对于有参数的block,当我们传递过去的时候, 它的需要接收方提供相应的参数才能运行,

这么做我们就可以在A类为B类将来会发生的事件提前做好处理的方法,即使我们还没有这些事件的具体参数.

某种意义上将这样就不需要两者之间的委托关系.

委托关系就是B类发生一个事件后,通知A类,让A类再针对这个事件进行一些处理

而使用block,则是A已经提前将这个事件的处理方法告诉了B类, 等时间发生的时候, B类无需通知A类, 直接运行实现设置好的处理方法(block)即可.

如果你在运行一个方法的时候又想告诉这个方法在某一特定情况你还要怎么做的话, 就可以使用Block.


D:

GCD:

GCD主要使用block来代替委托模式,使程序变得简洁,同时运行效率也得到提高.

    static int clickNum = ;
self.Mylabel = [[UILabel alloc]init];
while (clickNum <) {
dispatch_async(dispatch_get_main_queue(), ^{
self.Mylabel.text = [NSString stringWithFormat:@"%d",clickNum++];//UI的绘制必须在主线程中
});
[NSThread sleepForTimeInterval:];
}

关于block和GCD编程可以参考这篇文章:

还有这篇文章

ARC和非ARC中block的区别:

ARC下Block何时会从栈自动被复制到推, 以及__block和__weak的使用问题

由于Block是默认建立在栈上, 所以如果离开方法作用域, Block就会被丢弃, 在非ARC情况下, 我们要返回一个Block ,需要 [Block copy];
在ARC下, 以下几种情况, Block会自动被从栈复制到堆:
1.被执行copy方法
2.作为方法返回值
3.将Block赋值给附有__strong修饰符的id类型的类或者Blcok类型成员变量时
4.在方法名中含有usingBlock的Cocoa框架方法或者GDC的API中传递的时候.
对于非ARC下, 为了防止循环引用, 我们使用__block来修饰在Block中实用的对象:
__block id blockSelf=self;
self.blk=^{
NSLog(@"%@",blockSelf);  //在非ARC下对于栈上的_block对象, Block不会对其复制, 仅仅使用, 不会增加引用计数.
};
对于ARC下, 为了防止循环引用, 我们使用__weak来修饰在Block中实用的对象:
__weak id weakSelf=self;
self.blk=^{
NSLog(@"%@",weakSelf);
};
如果要在ARC下, 为了防止循环引用, 使用__block来修饰在Block中实用的对象,仍然会被retain, 所以需要多做一些设置
__block id blockSelf=self;
self.blk=^{
NSLog(@"%@",blockSelf);
self.blk=nil;   //blk被释放, blk只有的blockSelf也就被释放了
};
blk();   //并且一定要运行一次, 否则不能被释放
这样就使blk断开了与blockSelf的持有关系.
这么多好处是可以自己控制对self的持有时间.
不过在最新的ios版本中, 这些会始终被已叹号形式提示存在循环引用问题. 
这种书写方式不被推荐. 除非你要在block中修改__block的指针指向.
其实我们用使用__weak修饰符, 只是不能修改对象本身, 但是可以修改对象的属性. 

demo下载(还有点问题,暂时不提供下载)

【ios开发】Block编程的更多相关文章

  1. iOS开发--Block

    iOS开发--Block 1.什么是Block,block 的作用 ui开发和网络常见功能实现回调,按钮的事件处理方法是回调方法以及网络下载后的回调处理 (1)按钮 target-action   一 ...

  2. iOS开发——Block详解

    iOS开发--Block详解 1. Block是什么 代码块 匿名函数 闭包--能够读取其他函数内部变量的函数 函数变量 实现基于指针和函数指针 实现回调的机制 Block是一个非常有特色的语法,它可 ...

  3. ios开发 block语句块

    ios开发 block语句块 1.block 理解为匿名函数 2.block变量的定义 //定义block变量,^表示定义block //技巧:函数名左右加括号,在函数名前面在加^ void (^bl ...

  4. IOS开发——网络编程总汇

    关于IOS的网络编程,大家都会想到C实现的底层BSD ,CFNetwork和NSURL之类的库,虽然如今非常多第三方库非常方便,可是作为一名开发人员,也须要了解底层代码. 以下的思维导图是关于眼下开发 ...

  5. iOS 开发 之 编程知识点

    iOS 创建和设置pch iOS 之 时间格式与字符串转换 iOS 之 二维码生成与扫描(LBXScan) iOS 之 定时器 iOS 之 通知 iOS 之 NSString 去除前后空格和回车键 i ...

  6. iOS开发-Block回调

    关于Block之前有一篇文章已经写过一篇文章Object-C-代码块Block回顾,不过写的比较浅显,不能体现出Block在实际开发中的重要性,关于Block的基础知识,可以参考之前的博客.在实际开发 ...

  7. iOS开发——网络编程Swift篇&Alamofire详解

    Alamofire详解 预览图 Swift Alamofire 简介 Alamofire是 Swift 语言的 HTTP 网络开发工具包,相当于Swift实现AFNetworking版本. 当然,AF ...

  8. ios开发 网络编程浅析(一)

    iphone包含了很多框架和库,从底层的套接字到不同层次的封装,可以方便地给程序添加网络功能. (1)BSD套接字.最底层的套接字,这是Unix网络开发常用的API.如果从其他系统移植程序,而程序用的 ...

  9. iOS开发——网络编程OC篇&使用WebView构建HyBird应用

    使用WebView构建HyBird应用 HyBird是一种本地技术与Web相结合,能过实现跨平台的移动应用开发,最常用的一个框架:PhoneGap 一:首先,写好html代码 <!DOCTYPE ...

  10. iOS开发— Socket编程

    Socket编程 一.了解网络各个协议:TCP/IP.SOCKET.HTTP等 网络七层由下往上分别为物理层.数据链路层.网络层.传输层.会话层.表示层和应用层. 其中物理层.数据链路层和网络层通常被 ...

随机推荐

  1. Javascript学习4 - 对象和数组

    原文:Javascript学习4 - 对象和数组 在Javascript中,对象和数组是两种基本的数据类型,而且它们也是最重要的两种数据类型. 对象是已命名的值的一个集合,而数组是一种特殊对象,它就像 ...

  2. hdu 亲和串(kmp)

    Problem Description 人随着岁数的增长是越大越聪明还是越大越笨,这是一个值得全世界科学家思考的问题,同样的问题Eddy也一直在思考,因为他在很小的时候就知道亲和串如何判断了,但是发现 ...

  3. flume日志采集

    1.  Log4j Appender 1.1.  使用说明 1.1.2.  Client端Log4j配置文件 (黄色文字为需要配置的内容) log4j.rootLogger=INFO,A1,R # C ...

  4. hdu 3460 Ancient Printer

    Problem Description The contest is beginning! While preparing the contest, iSea wanted to print the ...

  5. 异步编程和线程的使用(.NET 4.5 )

    C#:异步编程和线程的使用(.NET 4.5 )   异步编程和线程处理是并发或并行编程非常重要的功能特征.为了实现异步编程,可使用线程也可以不用.将异步与线程同时讲,将有助于我们更好的理解它们的特征 ...

  6. Cocos2d-X采用CCScrollView创建滚动视图

    CCScrollView滚动视图可以让游戏有效果,并能够通过滚动视图切换游戏场景,滚动视图通常用来选择在游戏中的级别 实例1:使用CCScrollView创建一个简单的滚动视图 首先创建一个Scrol ...

  7. 自己定义GSON类型适配器

    Exception in thread "main" java.lang.RuntimeException: No-args constructor for class java. ...

  8. Android Fragment与Activity之间的数据交换(Fragment从Activity获取数据)

    Fragment与Activity之间的数据交换,通常含有3: 一.Fragment从Activity获取数据(仅本文介绍了一个第一): 两.Activity从Fragment获取数据: 三.Frag ...

  9. redis修改的源代码zincrby,hincrby命令

    在项目中大量使用zincrby命令.究其原因是统计一些统计指标的日志值,和需要返回到顺序topn. 通常情况下,.调用一次的指示器zincrby(zincrby default:type 1 type ...

  10. PyCharm 使用简介

    PyCharm 使用简介 最近由于项目需要,领导要求使用python以方便扩展,没有办法,赶鸭子上架花了2天时间翻完了python的初级教程然后就开始写代码.有一款好的IDE可以帮助我快速上手一门新语 ...