由浅到深的了解block

作为IOS开发者来说,你不会用block,真的就不能和其他小伙伴一块玩耍了,block运用随处可见,block这样的语法真的看起来很诡异,那么这个神奇的block(闭包)到底是何方神圣呢?各位看官,不要讲话,保留疑问,先看文章摘要,please静静的感受一下它的用法吧, go!!

本文章的概要

1. block的基本应用

2. block的typedef

3. block的作用

4. block运用过程中出现的问题以及如何规避

5. 深入了解block


  1. block的基本应用

    直观感受block跟函数很像,函数在调用前必须声名

void test3();

int main(int argc,constchar * argv[])

{

@autoreleasepool {

test3();

}

return0;

}

同样的block
同样也需要调用前必须声明

/**

定义了一个有返回值有参数的block

*/

void test3()

{

// 定义一个block计算两个整数的和

int (^sumBlock)(int,int) = ^(int
num1,int num2) {

return num1 + num2;

};

int c = sumBlock(10,9);

// 定义一个block计算一个整数的平方

int (^pinfangBlock)(int);

pinfangBlock = ^(int num){

return num * num;

};

pinfangBlock = ^(int num) {

return num +2;

};

int d = pinfangBlock(10);

NSLog(@"d is %d", d);

}

/**

定义了一个没有返回值但有参数的block

*/

void test2()

{

// 定义block变量,存储一段代码,这段代码的功能是能打印任意行数的****

void (^logStarBlock)(int) = ^(int numberOfLines){

for (int i =0; i<numberOfLines; i++) {

NSLog(@"***************");

}

};

logStarBlock(1);

}

/**

定义了一个没有返回值没有参数的block

*/

void test()

{

// 定义简单的block变量

// block跟函数很像:返回值、参数

void (^logStar)() = ^{

NSLog(@"***************");

NSLog(@"***************");

NSLog(@"***************");

};

logStar();

}

  1. block的typedef

    但是如果只是在函数体进行声明,调用,代码看起来不美观,感觉太乱了,所以需要typedef,这才是经常用的一种方式

// 定义一个叫做MyBlock的类型

// 利用MyBlock类型可以定义block变量

// 利用MyBlock类型定义出来的变量,存储的代码必须返回int,必须接受2个int类型的参数

typedef int (^MyBlock)(int,int);

int main(int argc,constchar * argv[])

{

@autoreleasepool {

MyBlock minusBlock = ^(int num1,int num2) {

return num1 - num2;

};

MyBlock multiBlock = ^(int num1,int num2) {

return num1 * num2;

};

multiBlock(10,1);

}

return0;

}

void test()

{

// 定义一个block来计算2个整数的差

int (^minusBlock)(int,int) = ^(int
num1,int num2) {

return num1 - num2;

};

// 定义一个block来计算2个整数的积

int (^multiBlock)(int,int) = ^(int
num1,int num2) {

return num1 * num2;

};

}

当然你也可以这样

typedef void(^tapBlock)(NSIndexPath*indexPath);

typedef void(^textBlock)(NSIndexPath*indexPath,NSString*text);

typedef  void(^pushTextViewBlock)(NSIndexPath*cellIndexPath,NSString*title,NSString*defaultText);

typedef  void(^showImageBlock)(NSIndexPath*indexPath,NSArray*
imageArr,NSInteger imgIndex);

typedef  void(^deletPhotoBlock)(NSIndexPath*indexPath,NSArray*imgArr,NSInteger
imgIndex);

typedef void(^scannerBlock)(NSString *scannerType);

typedef void (^SearchStaffBlock)(NSString *backTitle,NSArray
*cidArray,int tag);

typedef void(^SearchCustomMobile)(NSString *cidTitle,NSString
*title);

@interface CMDynomicCell :
UITableViewCell

@property(nonatomic,strong)NSIndexPath*
selectIndexPath;  //cell所在的indexPath;

@property(nonatomic,strong)textBlock
SingleLineText;      //单行文本的回调

@property(nonatomic,strong)textBlock
NumberText;          //数字文本的回调

@property(nonatomic,strong)pushTextViewBlock
pushTextView;//多行文本的回调

@end

调用self.textBlock=^(NSIndexPath*indexPath,NSString*text){

};

空外一种方式直接在方法上直接使用,这样看起来更加灵活了

-(void)noticeTaskList:(int)userId noticeId:(int)noticeId taskId:(int)taskId
success:(void(^)(id object))successBlock fail:(void(^)(NSString*
msg))failBlock;

-(void)noticeTaskList:(int)userId noticeId:(int)noticeId taskId:(int)taskId
success:(void(^)(id object))successBlock fail:(void(^)(NSString*
msg))failBlock{

if(successBlock) {

successBlock(id);

};

if(failBlock) {

failBlock(NSString*);

}

}

调用方式:

[[CMLoginHttpServicesharedInstance]login:usernamecompanyUsername:companyUsernamephone:phonepassword:passwordimei:imeiversionNo:versionNomobileName:mobileNamemobileType:mobileType success:^(id
object) {

} fail:^(NSString *msg) {

}];

使用方式总结

3. block的作用

1>重构代码,解耦合

#import <Foundation/Foundation.h>

typedef void (^WorkBlock)();

void goToWork(WorkBlock workBlock)

{

NSLog(@"起床");

NSLog(@"刷牙");

NSLog(@"穿衣服穿鞋");

NSLog(@"出门");

NSLog(@"搭公交");

NSLog(@"抵达公司");

// 实事

// 调用block之前一定要做判断

if (workBlock !=nil) {

workBlock();

}

// 实事

NSLog(@"叮咚叮咚下班了");

NSLog(@"搭公交");

NSLog(@"回家");

NSLog(@"睡觉");

}

/**

模拟星期一上班的具体情况

*/

void goToWorkInDay1()

{

goToWork(^{

NSLog(@"了解项目的需求");

});

}

void goToWorkInDay2()

{

// 实事

goToWork(^{

NSLog(@"熟悉公司以前的代码");

});

// 实事

}

void goToWorkInDay3()

{

// 实事

goToWork(^{

NSLog(@"开始编写代码");

});

// 实事

}

void test(int (^myblock)(int num1,double
num2, char num3))

{

}

int main(int argc,constchar * argv[])

{

@autoreleasepool {

////        goToWorkInDay3();

//        test(^int(int num1, double num2, char num3) {

//

//        });

//        WorkBlock block = ^{

//            NSLog(@"-------------------");

//        };

//

//        goToWork(block);

}

return0;

}

2>block 在实现时就会对它引用到的它所在方法中定义的栈变量进行一次只读拷贝,然后在 block 块内使用该只读拷贝。

- (void)testAccessVariable

{

NSInteger outsideVariable = 10;

//__block NSInteger outsideVariable = 10;

NSMutableArray * outsideArray = [[NSMutableArray alloc] init];

void (^blockObject)(void) = ^(void){

NSInteger insideVariable = 20;

KSLog(@"  > member variable = %d", self.memberVariable);

KSLog(@"  > outside variable = %d", outsideVariable);

KSLog(@"  > inside variable = %d", insideVariable);

[outsideArray addObject:@"AddedInsideBlock"];

};

outsideVariable = 30;

self.memberVariable = 30;

blockObject();

KSLog(@"  > %d items in outsideArray", [outsideArray count]);

}

输出结果:

3>在使用之前最好判断是否为nil,否则极有可能引起崩溃

参考来源

block注意事项及源代码

http://blog.csdn.net/allison162004/article/details/22850749

http://blog.csdn.net/fengsh998/article/details/38090205

5.深入了解block

以下这篇博客,写的这么这么深入也是没谁了!!

http://blog.devtang.com/2013/07/28/a-look-inside-blocks/

_____________________________________________________________________________________________

6.面试的block问题

Block的定义:

1> Block是OC中得一种数据类型,在iOS开发中被广泛使用.

2> ^是Block的特有标记.

3> Block的实现代码包含在{ }之间.

4> 大多数情况下,以内联inline函数的方式被定义和使用.

5> Block与C语言的指针有些相似,但使用更加灵活.

内联函数从源代码层看,有函数的结构,而在编译后,却不具备函数的性质.编译时,类似宏替代,使用函数体替换调用处的函数名;

Block封装了一段代码,可以在任何时候执行;

Block可以作为函数参数或者函数的返回值,而其本身又可以带输入参数或者返回值;

苹果官方建议尽量多使用block.在多线程,异步任务,集合遍历,集合排序,动画转场用得很多.

1 什么是block

nt (^yxpBlock)(int, int) =^(int a ) {return a*a ;};

说明:返回值(^语句块名称)(传人参数类型)=^(传人参数){主体};

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;

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

__block是一种特殊类型,

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

4 常见系列面试题

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

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

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

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();});

使用代码块的例子

第一个例子,假设我们创建一个纸牌游戏,需要展现纸牌被派发到玩家面前的动画效果。幸运的是通过UIKit框架可以很容易的实现一个动画效果。但是最终是什么样的动画是由你的程序决定的。你可以在代码块中指定动画的内容然后再将代码块传给animateWithDuration:animations:方法,像下面这样:

[UIView animateWithDuration:2.0

animations:^ {

self.cardView.alpha = 1.0;

self.cardView.frame = CGRectMake(176.0, 258.0, 72.0, 96.0);

self.cardView.transform = CGAffineTransformMakeRotation(M_PI);

}

];

当这个动画代码块执行时,我们的纸牌会展现三种方式的动画:改变它的alpha值从而淡入显示,改变它的位置到右下角(玩家的位置),以及自转180度(为了使其效果更好)。

第二个代码块的例子是迭代一个纸牌的集合,并打印其名字和在集合里的索引值。

你可以通过使用for循环来达到目的,但是在iOS4中NSArray类有一个使用了代码块的方便方法:enumerateObjectsUsingBlock:。下面是如何使用它:

NSArray *cards = [NSArray arrayWithObjects:@"Jack", @"Queen", @"King", @"Ace", nil];

[cards enumerateObjectsUsingBlock:^(id object, NSUInteger index, BOOL *stop) {

NSLog(@"%@ card at index %d", object, index);

}];

这个代码块使用了三个参数:数组中的一个对象,该对象的索引,以及一个标识迭代是否结束的标志。我们稍候再对其进一步探讨。enumerateObjectsUsingBlock: 这个方法会将集合中的每一个元素传入相应的参数并调用代码块中的方法。

时间: 2024-10-13 23:27:12

由浅到深的了解block的相关文章

Dagger 2从浅到深(七)

在使用Dagger 2开发时,一般都是在Application中生成一个AppComponent,然后其他的功能模块的Component依赖于AppComponent,作为AppComponent的子组件.可是,对于将自组建添加到父组件有两种方式: 通过@Component的dependencies属性依赖父组件 @Component(modules = OrangeModule.class, dependencies = FruitComponent.class) public interfa

浅入深出ElasticSearch构建高性能搜索架构

浅入深出ElasticSearch构建高性能搜索架构  课程学习地址:http://www.xuetuwuyou.com/course/161 课程出自学途无忧网:http://www.xuetuwuyou.com 一.课程用到的软件 ElasticSearch5.0.0 Spring Tool Suite 3.8.2.RELEASE Maven3.0.5 Spring4 Netty4 Hadoop2.7.1 Kibana5.0 JDK1.8.0_111 二.课程目标 1.快速学习Elastic

由浅到深学习JDBC二

封装数据访问对象 1:通过分析总结,所有对数据库表的操作都可以总结为通过JDBC对表的增删改查,为了减少冗余代码, 使得每次操作表时,不必都写JDBC程序,所以将对一张表的所有数据访功能,封装在数据访问对象 (Data Access Object)中,方便调用. 2:为了方便数据传输,往往会将java程序中所有相关操作的零散字段值,封装成一个实体对象--entity. 实体封装原则: 表----实体类 字段---属性 实现序列化 提供set,get方法. 以下代码就是利用Dao数据访问对象写出的

由浅到深学习JDBC一

JDBC: 虽然由于快节奏的开发,编程速度的追求,越爱越多的MVC框架出现,比如持久层的hibernate, mybatis等等,他们对Dao层的支持都很强大,既快速,又简便.但是他们的底层同样是使用了JDBC, 为了追求高速简便,我们可以不使用JDBC,但一定要了解JDBC.了解JDBC也有助于学习其他持久层框架. java和数据库交互需要中间程序作为中转.在很早以前,数据库厂商还没有一套统一的API作为 java语言和数据库的接口,开发程序是一件很头疼的事.对不同的数据库需要写不同的程序来作

SE壳C#程序-CrackMe-爆破 By:凉游浅笔深画眉 / Net7Cracker

[文章标题]: [SE壳C#程序-CrackMe-爆破]文字视频记录![文章作者]:  凉游浅笔深画眉[软件名称]: CM区好冷清,我来发一个吧!小小草莓[下载地址]: http://www.52pojie.cn/thread-243089-1-1.html[加壳方式]: SE壳[使用工具]: OD+WinHex+CFF Explorer[作者声明]: 只是感兴趣,没有其他目的.失误之处敬请诸位大侠赐教!思路来自吾爱大牛:Pnmker的教程谢谢!-------------------------

浅入深出之Java集合框架(下)

Java中的集合框架(下) 由于Java中的集合框架的内容比较多,在这里分为三个部分介绍Java的集合框架,内容是从浅到深,哈哈这篇其实也还是基础,惊不惊喜意不意外 ̄▽ ̄ 写文真的好累,懒得写了.. 温馨提醒:建议从(上)开始看哦~ 目 录 浅入深出之Java集合框架(上) 浅入深出之Java集合框架(中)   浅入深出之Java集合框架(下) 前 言 在<浅入深出之Java集合框架(中) >中介绍了Map接口的基本操作.使用的示例是在<浅入深出之Java集合框架(上)>中的模拟学

浅入深出之Java集合框架(上)

Java中的集合框架(上) 由于Java中的集合框架的内容比较多,在这里分为三个部分介绍Java的集合框架,内容是从浅到深,如果已经有java基础的小伙伴可以直接跳到<浅入深出之Java集合框架(下)>. 目录: 浅入深出之Java集合框架(上) 浅入深出之Java集合框架(中)   努力赶制中..关注后更新会提醒哦! 浅入深出之Java集合框架(下) 努力赶制中..关注后更新会提醒哦! 一.集合概述 1)集合的概念 现实生活中的集合:很多事物凑在一起. 数学中的集合:具有共同属性的事物的总体

浅入深出之Java集合框架(中)

Java中的集合框架(中) 由于Java中的集合框架的内容比较多,在这里分为三个部分介绍Java的集合框架,内容是从浅到深,如果已经有java基础的小伙伴可以直接跳到<浅入深出之Java集合框架(下)>. 目 录 浅入深出之Java集合框架(上) 浅入深出之Java集合框架(中)   浅入深出之Java集合框架(下) 努力赶制中..关注后更新会提醒哦! 前 言 在<浅入深出之Java集合框架(上)>中介绍了List接口和Set接口的基本操作,在这篇文章中,我将介绍关于Map接口的基

『浅入深出』MySQL 中事务的实现

在关系型数据库中,事务的重要性不言而喻,只要对数据库稍有了解的人都知道事务具有 ACID 四个基本属性,而我们不知道的可能就是数据库是如何实现这四个属性的:在这篇文章中,我们将对事务的实现进行分析,尝试理解数据库是如何实现事务的,当然我们也会在文章中简单对 MySQL 中对 ACID 的实现进行简单的介绍. 事务其实就是并发控制的基本单位:相信我们都知道,事务是一个序列操作,其中的操作要么都执行,要么都不执行,它是一个不可分割的工作单位:数据库事务的 ACID 四大特性是事务的基础,了解了 AC