IOS中Block用法介绍

IOS中Block用法介绍


1 什么是block

Block iOS4.0之后新增的程式语法,严格来说block的概念并不算是基础程式设计的范围.BlockC级别的语法和运行时特性。Block比较类似C函数,但是Block比之C函数,其灵活性体现在栈内存、堆内存的引用,我们甚至可以将一个Block作为参数传给其他的函数或者Block

引用网上例子:

  1: int multiplier = 7 ;

   2: int (^myBlock)( int ) = ^( int num)

   3: {

   4:     return num * multiplier;

   5: };


语法介绍:

我们使用「^」运算子来宣告一个block变数,而且在block的定义最后面要加上「;」来表示一个完整的述句.

我们宣告一个「myBlock」变数,用「^」符号来表示这是一个block

这是block的完整定义,这个定义将会指定给「myBlock」变数。

表示「myBlock」是一个回传值为整数(int)的block

它有一个参数,型态也是整数。

这个参数的名字叫做「num」。

这是block的内容。


  1. typedef void (^BoolBlock)(BOOL);//一个只接受一个BOOL参数,没有返回值的block 
  2. typedef int (^IntBlock)(void);//一个没有参数,返回intblock 
  3. typedef BoolBlock (^HugeBlock)(IntBlock);//看看,这个HugeBlock的参数和返回值都是block 

  1. - (void)someMethod 
  2.     BoolBlock ablock = ^(BOOL bValue) { 
  3.         NSLog(@"Bool block!"); 
  4.     }; 
  5.     ablock(); 


 __block 变量:

block内只能读取在同一个作用域的变数而且没有办法修改在block外定义的任何变数,此时若我们想要这些变数能够在block中被修改,就必须在前面挂上__block的修饰词,


1: __block int multiplier = 7 ;

   2: int (^myBlock)( int ) = ^( int num)

   3:                         {

   4:                             if (num > 5 )

   5:                             {

   6:                                   multiplier = 7 ;

   7:                             }

   8:                             else

   9:                             {

  10:                                   multiplier = 10 ;

  11:                             }

  12:                             return num * multiplier;

  13:                         };

 

Block 概要

 

Block 提供我们一种能够将函数程式码内嵌在一般述句中的方法,在其他语言中也有类似的概念称做「closure」,但是为了配合Objective-C的贯例,我们一律将这种用法称为「block

Block 的功能

Block 是一种具有匿名功能的内嵌函数,它的特性如下:

如一般的函数般能拥有带有型态的参数。

拥有回传值。

可以撷取被定义的词法作用域(lexical scope)状态。

可以选择性地修改词法作用域的状态。

注:词法作用域(lexical scope)可以想像成是某个函数两个大括号中间的区块,这个区块在程式执行时,系统会将这个区块放入堆叠记忆体中,在这个区块中的宣告的变数就像是我们常听到的区域变数,当我们说block可以撷取同一词法作用域的状态时可以想像block变数和其他区域变数是同一个层级的区域变数(位于同一层的堆叠里),而block的内容可以读取到和他同一层级的其他区域变数。

我们可以拷贝一个block,也可以将它丢到其他的执行绪中使用,基本上虽然blockiOS程式开发中可以使用在C/C++开发的程式片段,也可以在Objective-C中使用,不过在系统的定义上,block永远会被视为是一个Objective-C的物件。


Block 的使用时机

Block 一般是用来表示、简化一小段的程式码,它特别适合用来建立一些同步执行的程式片段、封装一些小型的工作或是用来做为某一个工作完成时的回传呼叫(callback 

在新的iOS APIblock被大量用来取代传统的delegatecallback,而新的API会大量使用block主要是基于以下两个原因:

可以直接在程式码中撰写等会要接着执行的程式,直接将程式码变成函数的参数传入函数中,这是新API最常使用block的地方。

可以存取区域变数,在传统的callback实作时,若想要存取区域变数得将变数封装成结构才能使用,而block则是可以很方便地直接存取区域变数。


宣告和建立Block

 

宣告Block的参考(Reference

Block 变数储存的是一个block的参考,我们使用类似宣告指标的方式来宣告,不同的是这时block变数指到的地方是一个函数,而指标使用的是「*」,block则是使用「^」来宣告,下面是一些合法的block宣告:

   1: /* 回传void ,参数也是void 的block*/

    2: void (^blockReturningVoidWithVoidArgument)( void );

   3: /* 回传整数,两个参数分别是整数和字元型态的block*/

   4: int   (^blockReturningIntWithIntAndCharArguments)( int , char );

   5: /* 回传void ,含有10 个block 的阵列,每个block 都有一个型态为整数的参数*/

   6: void (^arrayOfTenBlocksReturningVoidWinIntArgument[ 10 ])( int );

   7: X.3.2 建立一个Block 

   9: 我们使用「^」来开始一个block,并在最后使用「;」来表示结束,下面的范例示范了一个block变数,然后再定义一个block把它指定给block变数: 

  10:  

  11: int (^oneFrom)( int ); /* 宣告block 变数*/

  12:     /* 定义block 的内容并指定给上面宣告的变数*/

  13:     oneFrom = ^(int anInt)

  14:                 {

  15:                     return anInt = - 1 ; 

  16:                 };



Block当作函数的参数

我们可以像使用一般函数使用参数的方式,将block以函数参数的型式传入函数中,在这种情况下,大多数我们使用block的方式将不会倾向宣告block而是直接以内嵌的方式来将block传入,这也是目前新版SDK中主流的做法,我们将补充前面章节的例子来说明:

   1: char *myCharacters[ 3 ] = { "TomJohn" , "George" , "Charles Condomine" };

   2: qsort_b (myCharacters, 3 , sizeof ( char *),

   3:             ^( const void *l, const void *r)

   4:             {

   5: char *left = *( char **)l;

   6: char *right = *( char **)r;

   7: return strncmp (left, right, 1 );

   8:             } // 这里是block 的终点。

   9:             );

  10: // 最后的结果为:{"Charles Condomine", "George", "TomJohn"}

在上面的例子中,block本身就是函数参数的一部分,在下一个例子中dispatch_apply函数中使用blockdispatch_apply的定义如下:

    1: void

   2: dispatch_apply( size_t iterations, dispatch_queue_t queue, void (^block)( size_t ));

   3: 这个函数将一个block提交到发送伫列(dispatch queue)中来执行多重的呼叫,只有当伫列中的工作都执行完成后才会回传,这个函数拥有三个变数,而最后一个参数就是block ,请参考下面的范例: 

   4:  

   5: size_t count = 10 ;

   6: dispatch_queue_t queue =

   7: dispatch_get_global_queue ( DISPATCH_QUEUE_PRIORITY_DEFAULT , 0 );

   8: dispatch_apply (count, queue, ^( size_t i) {

   9: printf ( "%u\n" , i);

  10:     });

Block当作方法的参数

SDK中提供了许多使用block的方法,我们可以像传递一般参数的方式来传递block,下面这个范例示范如何在一个阵列的前5笔资料中取出我们想要的资料的索引值:

   1: // 所有的资料

   2: NSArray *array = [ NSArray arrayWithObjects : @"A" , @"B" , @"C" , @"A" , @"B" , @"Z" , @"G" , @"are" , @" Q" ,nil ];   

   3: // 我们只要这个集合内的资料

   4: NSSet *filterSet = [ NSSet setWithObjects : @"A" , @"B" , @"Z" , @"Q" , nil ];

   5: BOOL (^test)( id obj, NSUInteger idx, BOOL *stop);

   6: test = ^ ( id obj, NSUInteger idx, BOOL *stop) {

   7: // 只对前5 笔资料做检查

   8: if (idx < 5 ) {

   9: if ([filterSet containsObject : obj]) {

  10: return YES ;

  11:               }

  12:       }

  13: return NO ;

  14: };

  15: NSIndexSet *indexes = [array indexesOfObjectsPassingTest :test];

  16: NSLog ( @"indexes: %@" , indexes);   

  17: // 结果:indexes: <NSIndexSet: 0x6101ff0>[number of indexes: 4 (in 2 ranges), indexes: (0-1 3-4)]

  18: // 前5笔资料中,有4笔符合条件,它们的索引值分别是0-1, 3-4


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值