ios block中return里面不能用return吗?如何修改呢

benjielin 的BLOG
用户名:benjielin
文章数:240
评论数:331
访问量:688041
注册日期:
阅读量:5863
阅读量:12276
阅读量:315247
阅读量:1028761
51CTO推荐博文
Block可以帮助我们组织独立的代码段,并提高复用性和可读性。iOS4在UIKit中引入了该特征。超过100个的Apple API都使用了Block,所以这是一个我们必须开始熟悉的知识。
Block是什么样的?
你可以使用^操作符来声明一个Block变量,它表示一个Block的开始。
int&num1&=&7; &int(^aBlock)(int)&=&^)int&num2)&{ &&&&return&num1+nunm2; &};&&
在如上代码中我们将Block声明为一个变量,所以可以将它当做一个函数中使用:
NSLog(@&%d&,&aBlock(49));&//adds&49&to&7&which&gives&us&56.&&
我们刚看过了将block当做变量的情况,但通常情况下我们会以内联的方式使用Block,比如在一个变量中。API要么会使用Block在一个对象集合上执行某种操作,要么将其作为一个操作完成后的回调。
NSComperator&compareStringsBlock&=&^(id&stringA,&id&stringB)&{ &NSRange&rangeS&&=&NSMakeRange&(0,&[stringA&length]); &&&return&(stringA&compare:stringB&options:comparisonOptions&range:rangeS&locale:currentLocale]; &}; &&NSArray&*compareSortArray&&=&[arrayOfStringDays&sortArrayUsingComparator:&compareStringsBlock]);&&
Block具有将临时函数体创建为表达式的优势。Apple文档中指出:
Block是符合如下要求的匿名内联的代码集:
和函数一样具有一个指定类型的参数列表
&有一个可以推导或声明的返回值类型
可以从它被定义的词义范围中捕捉状态
可以在需要的时候改变词义范围的状态
可以和相同的词义范围中定义的其他的Block共享更改的可能。
可以在词义范围(堆栈帧)被销毁后继续共享和修改该词义范围(堆栈帧)的状态。
Block是一个自包含的小代码段,封装了用于遍历(线性遍历)或者回调,可以并发执行的任务单元。
声明和使用Block
Apple文档中介绍了如何将一个Block声明为变量,并将其作为一个函数使用:
int&(^oneFrom)(int)&=&^(int&anInt)&{ &&&&&return&anInt&-&1; &}; &//&我们创建了一个内联块^(int&anInt)...&,其函数体和结果被传到了另外一个名为OneFrom的Block。 &&printf(&1&from&10&is&%d&,&oneFrom(10)); &//&打印出:&&1&from&10&is&9& &//&这个block函数(distanceTraveled)传入3个float型参数,返回float值。& &&float&(^distanceTraveled)&(float,&float,&float)&= &&&&&&&&&&&&&&&&&&&&&&&&&&&&^(float&startingSpeed,&float&acceleration,&float&time)&{ &&&&&float&distance&=&(startingSpeed&*&time)&+&(0.5&*&acceleration&*&time&*&time); &&&&&return& &};&
& 你也可以传入一个Block作为一个参数,而不要以如上的方式声明它们,这样就可以在需要将block作为参数的时候以内联代码的方式简单地实现。
NSArray&*anArray&=&[NSArray&arrayWithObjects:&@&cat&,&@&dog&,nil]; &sortFunction(anArray,&^(string&*a&string&*b){ &if&(&a&==&@&cat&)&return&TRUE;&});&
这样我们就看到一个内联的block代码段占据了最后一个参数(必须是参数列表的最后一个参数)的位置。Cocoa提供了很多使用Block的方法,这样你就可以传入Block作为方法的参数:
NSArray&*array&=&[NSArray&arrayWithObjects:&@&A&,&@&B&,&@&C&,&&nil]; &NSSet&*filterSet&=&[NSSet&setWithObjects:&@&A&,&@&Z&,&@&Q&,&nil]; &&BOOL&(^test)(id&obj,&NSUInteger&idx,&BOOL&*stop);&//Block&declaration&returns&BOOL,&params&inc.&id&and&BOOL &//body&of&block&gets&the&block&literal&^(id&obj,&NSUInteger&idx,&Bool&*stop)...&and&the&body&logic& &test&=&^&(id&obj,&NSUInteger&idx,&BOOL&*stop)&{ &&&&&if&(idx&&&5)&{ &&&&&&&&&if&([filterSet&containsObject:&obj])&{ &&&&&&&&&&&&&return&YES; &&&&&&&&&} &&&&&} &&&&&return&NO; &&};&
Apple提供的另外一个例子是:
__block&BOOL&found&=&NO; &NSSet&*aSet&=&[NSSet&setWithObjects:&@&Alpha&,&@&Beta&,&@&Gamma&,&@&X&,&nil]; &NSString&*string&=&@&gamma&; &//we&provide&below&a&way&of&how&to&enumerate,&using&our&own&compare&logic &[aSet&enumerateObjectsUsingBlock:^(id&obj,&BOOL&*stop)&{ &&&&&if&([obj&localizedCaseInsensitiveCompare:string]&==&NSOrderedSame)&{ &&&&&&&&&*stop&=&YES; &&&&&&&&&found&=&YES; &&&&&} &}];&
掌握它需要一点时间,但一旦领会了还是很简答的,是不?我建议大家看下Apple的文档,并看看其中引用到的一些API以确认下它们是如何使用的。多练习,熟能生巧!
原文出处:
了这篇文章
类别:未分类┆阅读(0)┆评论(0)javascript(5)
首先return作为返回关键字,他有以下两种返回方式
1.返回控制与函数结果
语法为:return
表达式; 语句结束函数执行,返回调用函数,而且把表达式的值作为函数的结果
2.返回控制无函数结果
语法为:在大多数情况下,为事件处理函数返回false,可以防止默认的事件行为.例如,默认情况下点击一个&A&元素,页面会跳转到该元素href属性指定的页. return false 就相当于终止符,return true 就相当于执行符。在js中return false的作用一般是用来取消默认动作的。比如你单击一个链接除了触发你的&onclick&事件以外还要触发一个默认事件就是执行页面的跳转。所以如果你想取消对象的默认动作就可以return
false。也就是说如果你想用JS代码来局部改变一些数据而不引起页面其他部位的变化,那么你就应该在该onclick事件代码的后面加上return false;
在js中,我们常用return false来阻止提交表单或者继续执行下面的代码,通俗的来说就是阻止执行默认的行为。 例如下面的例子:
function s1(){
if(true)
},这是没有任何问题的。
function s2(){
即使m函数返回return false 阻止提交了,但是不影响 n()以及 p()函数的执行。在s2()函数里调用m()函数,那面里的return false 对于s2()函数来说,只是相当于返回值。而不能阻止s2()函数执行。&return false 只在当前函数有效,不会影响其他外部函数的执行。
总的来说在js中对于return用法的三种情况的总结如下:
retrun true; 返回正确的处理结果。
return false;返回错误的处理结果;终止处理;阻止提交表单;阻止执行默认的行为。
return;把控制权返回给页面。
下面举一个自己在开发中遇到的实例:
在JS中我有一个按钮的触发事件
&input type=&button& value=&改变颜色& onclick=&changeColor(this)&&
这个按钮的原本功能是为了点击后改变界面上该按钮的颜色,但是这样在实际操作中并未实现想要达到的效果,后来结果调试和查阅资料,了解了JS中关于return的用法后,做了如下修改:
&input type=&button& value=&改变颜色& onclick=&changeColor(this);return false;&&
这样就达到了预期的效果。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:7938次
排名:千里之外
原创:17篇
转载:61篇
(4)(4)(3)(5)(1)(6)(8)(11)(4)(2)(5)(6)(7)(12)随笔 - 58&
文章 - 0&评论 - 17&trackbacks - 0
本文来自台湾的某开发人员的博客,被墙,感觉讲的比较易懂,所以引过来。文字简体化了,原来是繁体,变数=变量,这个注意一下。
本文的顺序是层层深入的,要想简单的了解,只看X.1 初探Block就好了
本章学习目标:
1. 了解何谓block。
2. 了解block的使用方法。
Block 是iOS在4.0之后新增的程式语法,严格来说block的概念并不算是基础程式设计的范围,对初学者来说也不是很容易了解,但是在iOS SDK 4.0之后,block几乎出现在所有新版的API之中,换句话说,如果不了解block这个概念就无法使用SDK 4.0版本以后的新功能,因此虽然block本身的语法有点难度,但为了使用iOS的新功能我们还是得硬着头皮去了解这个新的程式概念。
在这一章的目标以了解如何使用block为主而不深入探讨block底层的运作方式,至于有些初学者较少遇到的辞汇如「词法作用域(lexical scope)」等,本章将不再多做解释,待有兴趣的读者去请教Google大神吧。
X.1 初探Block
在这一小节我们先用一些简单范例来导入block的概念。
X.1.1 宣告和使用Block
我们使用「^」运算子来宣告一个block变数,而且在block的定义最后面要加上「;」来表示一个完整的述句(也就是将整个block定义视为前面章节所介绍的简单述句,因为整个定义必须是一个完整的句子,所以必须在最后面加上分号),下面是一个block的范例:
1: int multiplier = 7 ;
2: int (^myBlock)( int ) = ^( int num)
return num *
我们使用下图来解释这个范例(请将文字框的字翻译如下):
我们宣告一个「myBlock」变数,用「^」符号来表示这是一个block。
这是block的完整定义,这个定义将会指定给「myBlock」变数。
表示「myBlock」是一个回传值为整数(int)的block。
它有一个参数,型态也是整数。
这个参数的名字叫做「num」。
这是block的内容。
值得注意的地方是block可以使用和本身定义范围相同的变数,可以想像在上面的例子中 multiplier 和 myBlock 都是某一个函数内定义的两个变数也就是这个变数都在某个函数两个大括号「{」和「 }」中间的区块,因为它们的有效范围是相同的,因此在block中就可以直接使用 multiplier 这个变数,此外当把block定义成一个变数的时,我们可以直接像使用一般函数般的方式使用它:
1: int multiplier = 7 ;
2: int (^myBlock)( int ) = ^( int num)
return num *
6: printf ( "%d" , myBlock( 3 ));
7: //结果会打印出21
X.1.2 直接使用Block
在很多情况下,我们并不需要将block宣告成变数,反之我们可以直接在需要使用block的地方直接用内嵌的方式将block的内容写出来,在下面的例子中qsort_b函数,这是一个类似传统的qsort_t函数,但是直接使用block做为它的参数:
1: char *myCharacters[ 3 ] = { "TomJohn" , "George" , "Charles Condomine" };
2: qsort_b (myCharacters, 3 ,
sizeof ( char *),
^( const void *l, const void *r)//block部分
char *left = *( char **)l;
char *right = *( char **)r;
return strncmp (left, right, 1 );
X.1.3 __block 变量
一般来说,在block内只能读取在同一个作用域的变数而且没有办法修改在block外定义的任何变数,此时若我们想要这些变数能够在block中被修改,就必须在前面挂上__block的修饰词,以上面第一个例子中的 multiplier 来说,这个变数在 block 中是唯读的,所以 multiplier = 7 指定完后,在 block 中的 multiplier 就只能是 7 不能修改,若我们在 block 中修改 multiplier ,在编辑时就会产生错误,因此若想要在 block 中修改 multiplier ,就必须在 multiplier 前面加上 __block 的修饰词,请参考下面的范例:
1: __block int multiplier = 7 ;
2: int (^myBlock)( int ) = ^( int num)
if (num & 5 )
multiplier = 7 ;
multiplier = 10 ;
return num *
X.2 Block 概要
Block 提供我们一种能够将函数程式码内嵌在一般述句中的方法,在其他语言中也有类似的概念称做「closure」,但是为了配合Objective-C的贯例,我们一律将这种用法称为「block」
X.2.1 Block 的功能
Block 是一种具有匿名功能的内嵌函数,它的特性如下:
如一般的函数般能拥有带有型态的参数。
拥有回传值。
可以撷取被定义的词法作用域(lexical scope)状态。
可以选择性地修改词法作用域的状态。
注:词法作用域(lexical scope)可以想像成是某个函数两个大括号中间的区块,这个区块在程式执行时,系统会将这个区块放入堆叠记忆体中,在这个区块中的宣告的变数就像是我们常听到的区域变数,当我们说block可以撷取同一词法作用域的状态时可以想像block变数和其他区域变数是同一个层级的区域变数(位于同一层的堆叠里),而block的内容可以读取到和他同一层级的其他区域变数。
我们可以拷贝一个block,也可以将它丢到其他的执行绪中使用,基本上虽然block在iOS程式开发中可以使用在C/C++开发的程式片段,也可以在Objective-C中使用,不过在系统的定义上,block永远会被视为是一个Objective-C的物件。
X.2.2 Block 的使用时机
Block 一般是用来表示、简化一小段的程式码,它特别适合用来建立一些同步执行的程式片段、封装一些小型的工作或是用来做为某一个工作完成时的回传呼叫(callback) 。
在新的iOS API中block被大量用来取代传统的delegate和callback,而新的API会大量使用block主要是基于以下两个原因:
可以直接在程式码中撰写等会要接着执行的程式,直接将程式码变成函数的参数传入函数中,这是新API最常使用block的地方。
可以存取区域变数,在传统的callback实作时,若想要存取区域变数得将变数封装成结构才能使用,而block则是可以很方便地直接存取区域变数。
X.3 宣告和建立Block
X.3.1 宣告Block的参考(Reference)
Block 变数储存的是一个block的参考,我们使用类似宣告指标的方式来宣告,不同的是这时block变数指到的地方是一个函数,而指标使用的是「*」,block则是使用「^」来宣告,下面是一些合法的block宣告:
1: /* 回传void ,参数也是void 的block*/
2: void (^blockReturningVoidWithVoidArgument)( void );
3: /* 回传整数,两个参数分别是整数和字元型态的block*/
(^blockReturningIntWithIntAndCharArguments)( int , char );
5: /* 回传void ,含有10 个block 的阵列,每个block 都有一个型态为整数的参数*/
6: void (^arrayOfTenBlocksReturningVoidWinIntArgument[ 10 ])( int );
7: X.3.2 建立一个Block
9: 我们使用「^」来开始一个block,并在最后使用「;」来表示结束,下面的范例示范了一个block变数,然后再定义一个block把它指定给block变数:
11: int (^oneFrom)( int ); /* 宣告block 变数*/
/* 定义block 的内容并指定给上面宣告的变数*/
oneFrom = ^(int anInt)
return anInt = - 1 ;
X.3.3 全域的Block
我在可以在档案中宣告一个全域的block,请参考以下范例:
1: int GlobalInt = 0 ;
2: int (^getGlobalInt)( void ) = ^ ( void ) { return GlobalI};
X.4 Block 和变量
接下来的这一小节我们将会介绍block和变数之间的互动。
X.4.1 变数的型态
我们可以在block中遇到平常在函数中会遇到的变数类型:
l 全域(global)变数或是静态的区域变数(static local)。
l 全域的函数。
l 区域变数和由封闭领域(enclosing scope)传入的参数。
除了上述之外block额外支援了另外两种变数:
在函数内可以使用__block 变数,这些变数在block中是可被修改的。
汇入常数(const imports)。
此外,在方法的实作里,block可以使用Objective-C的实体变数(instance variable)。
下列的规则可以套用到在block中变数的使用:
可以存取全域变数和在同一领域(enclosing lexical scope)中的静态变数。
可以存取传入block的参数(使用方式和传入函数的参数相同)。
在同一领域的区域变数在block中将视为常数(const)。
可以存取在同一领域中以__block 为修饰词的变数。
在block中宣告的区域变数,使用方式和平常函数使用区域变数的方式相同。
下面的例子介绍了区域变数(上述第三点)的使用方式:
1: int x = 123 ;
2: void (^printXAndY)( int ) = ^( int y)
4: printf ( "%d %d\n" , x, y);
6: // 将会印出123 456
printXAndY( 456 );
8: 就如上面第三点所提到的,在上例中的int x = 123的变量x,在传入block后将视同常数,因此若我们在block中试着去修改x的值时就会产生错误,下面的例子将会无法通过编译:
10: int x = 123 ;
11: void (^printXAndY)( int ) = ^( int y)
// 下面这一行是错的,因为x 在这是一个常数不能被修改。
printf ( "%d %d\n" , x, y);
若在block中想要修改上面的变数x,必须将x宣告加上修饰词__block,请参考接下来这一小节的介绍。
X.4.2 __block 型态变数
我们可以藉由将一个由外部汇入block的变数放上修饰词__block来让这个变数由唯读变成可以读和写,不过有一个限制就是传入的变数在记忆体中必须是一个占有固定长度记忆体的变数,__block修饰词无法使用于像是变动长度的阵列这类不定长度的变数,请参考下面的范例:
1: // 加上__block 修饰词,所以可以在block 中被修改。
2: __block int x = 123 ;
3: void (^printXAndY)( int ) = ^( int y)
6: printf ( "%d %d\n" , x, y);
8: // 将会印出579 456
printXAndY( 456 );
10: //x 将会变成 579;
11: 下面我们使用一个范例来介绍各类型的变数和block之间的互动:
13: extern NSInteger CounterG
14: static NSInteger CounterS
16: NSInteger localCounter = 42 ;
17: __block char localC
18: void (^aBlock)( void ) = ^( void )
++ CounterG //可以存取。
++ CounterS //可以存取。 
22: CounterGlobal = localC //localCounter在block 建立时就不可变了。
localCharacter = 'a' ; //设定外面定义的localCharacter 变数。
++localC //不会影响的block 中的值。
localCharacter = 'b' ;
aBlock(); //执行block 的内容。
28: //执行完后,localCharachter 会变成'a'
X.4.3 物件和Block变数
Block 支援在Objective-C、C++物件和其他block中当作变数来使用,不过因为在大部分的情况我们都是使用Objective-C的撰写程式,因此在这一小节我们仅针对Objective-C的情况进行介绍,至于其他两种情况就留给有兴趣的读者再自行深入研究了。
x.4.3.1 Objective-C 物件
在拥有参考计数(reference-counted)的环境中,若我们在block中参考到Objective-C的物件,在一般的情况下它将会自动增加物件的参考计数,不过若以__block为修饰词的物件,参考计数则是不受影响。
如果我们在Objective-C的方法中使用block时,以下几个和记忆体管理的事是需要额外注意的:
l 若直接存取实体变数(instance variable),self的参考计数将被加1。
l 若透过变数存取实体变数的值,则只变数的参考计数将被加1。
以下程式码说明上面两种情况,在这个假设instanceVariable是实体变数:
1: dispatch_async (queue, ^{
2: // 因为直接存取实体变数instanceVariable ,所以self 的retain count 会加1
3: doSomethingWithObject (instanceVariable);
5: id localVaribale = instanceV
6: dispatch_async (queue, ^{
7: //localVariable 是存取值,所以这时只有localVariable 的retain count 加1
8: //self 的 return count  并不会增加。
9: doSomethingWithObject (localVaribale);
X.5 使用Block
这一小节我们将会对block的使用方式做一些初步的介绍
X.5.1 呼叫一个Block
当block宣告成一个变数时,我们可以像使用一般函数的方式来使用它,请参考下面两个范例:
1: int (^oneFrom)( int ) = ^( int anInt) {
2: return anInt - 1 ;
4: printf ( "1 from 10 is %d" , oneFrom( 10 ));
5: //结果会显示:1 from 10 is 9
6: float (^distanceTraveled)( float , float , float ) = ^( float startingSpeed, float acceleration, float time)
8: float distance = (startingSpeed * time) + ( 0.5 * acceleration * time * time);
11: float howFar = distanceTraveled( 0.0 , 9.8 , 1.0 );
12: //howFar会变成4.9
在一般常见的情况中,若是将block当做是参数传入函数,我们通常会使用「内嵌」的方式来使用block。
X.5.2 将Block当作函数的参数
我们可以像使用一般函数使用参数的方式,将block以函数参数的型式传入函数中,在这种情况下,大多数我们使用block的方式将不会倾向宣告block而是直接以内嵌的方式来将block传入,这也是目前新版SDK中主流的做法,我们将补充前面章节的例子来说明:
1: char *myCharacters[ 3 ] = { "TomJohn" , "George" , "Charles Condomine" };
2: qsort_b (myCharacters, 3 , sizeof ( char *),
^( const void *l, const void *r)
5: char *left = *( char **)l;
6: char *right = *( char **)r;
7: return strncmp (left, right, 1 );
} // 这里是block 的终点。
10: // 最后的结果为:{"Charles Condomine", "George", "TomJohn"}
在上面的例子中,block本身就是函数参数的一部分,在下一个例子中dispatch_apply函数中使用block,dispatch_apply的定义如下:
2: dispatch_apply( size_t iterations, dispatch_queue_t queue, void (^block)( size_t ));
3: 这个函数将一个block提交到发送伫列(dispatch queue)中来执行多重的呼叫,只有当伫列中的工作都执行完成后才会回传,这个函数拥有三个变数,而最后一个参数就是block ,请参考下面的范例:
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);
X.5.3 将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 ;
13: return NO ;
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
X.5.4 该避免的使用方式
在下面的例子中,block是for回圈的区域变数因此在使用上必须避免将区域的block指定给外面宣告的block:
1: // 这是错误的范例,请勿在程式中使用这些语法!!
2: void dontDoThis() {
void (^blockArray[3])(void); // 3 个block 的阵列
for (int i = 0; i & 3; ++i) {
blockArray[i] = ^{ printf("hello, %d\n", i); };
// 注意: 这个block 定义仅在for 回圈有效。
9: void dontDoThisEither() {
void (^block)(void);
int i = random():
if (i & 1000) {
block = ^{ printf("got i at: %d\n", i); };
// 注意: 这个block 定义仅在if 后的两个大括号中有效。
阅读(...) 评论()如何在iOS中使用block
如何在iOS中使用Block&
Block可以帮助我们组织独立的代码段,并提高复用性和可读性。iOS4在UIKit中引入了该特征。超过100个的Apple
API都使用了Block,所以这是一个我们必须开始熟悉的知识。&
Block是什么样的?&
你可以使用^操作符来声明一个Block变量,它表示一个Block的开始。&
在如上代码中我们将Block声明为一个变量,所以可以将它当做一个函数中使用:&
我们刚看过了将block当做变量的情况,但通常情况下我们会以内联的方式使用Block,比如在一个变量中。API要么会使用Block在一个对象集合上执行某种操作,要么将其作为一个操作完成后的回调。&
NSComperator compareStringsBlock = ^(id stringA, id stringB) {
NSRange rangeS = NSMakeRange (0, [stringA length]);
return (stringA compare:stringB options:comparisonOptions
range:rangeS locale:currentLocale]; &
NSArray *compareSortArray = [arrayOfStringDays
sortArrayUsingComparator: compareStringsBlock]);
Block具有将临时函数体创建为表达式的优势。Apple文档中指出:&
Block是符合如下要求的匿名内联的代码集:&
和函数一样具有一个指定类型的参数列表
  有一个可以推导或声明的返回值类型
可以从它被定义的词义范围中捕捉状态
可以在需要的时候改变词义范围的状态
可以和相同的词义范围中定义的其他的Block共享更改的可能。
可以在词义范围(堆栈帧)被销毁后继续共享和修改该词义范围(堆栈帧)的状态。
Block是一个自包含的小代码段,封装了用于遍历(线性遍历)或者回调,可以并发执行的任务单元。&
声明和使用Block&
Apple文档中介绍了如何将一个Block声明为变量,并将其作为一个函数使用:&
int (^oneFrom)(int) = ^(int anInt) { &
  return anInt - 1;
// 我们创建了一个内联块^(int anInt)... ,其函数体和结果被传到了另外一个名为OneFrom的Block。
printf("1 from 10 is %d", oneFrom(10)); &
// 打印出: "1 from 10 is 9" &
// 这个block函数(distanceTraveled)传入3个float型参数,返回float值。
float (^distanceTraveled) (float, float, float) =
  ^(float startingSpeed, float acceleration, float time) {
  floatdistance = (startingSpeed * time) (0.5 * acceleration *
time * time); &
  你也可以传入一个Block作为一个参数,而不要以如上的方式声明它们,这样就可以在需要将block作为参数的时候以内联代码的方式简单地实现。
这样我们就看到一个内联的block代码段占据了最后一个参数(必须是参数列表的最后一个参数)的位置。Cocoa提供了很多使用Block的方法,这样你就可以传入Block作为方法的参数:&
NSArray *array = [NSArray arrayWithObjects: @"A", @"B", @"C",
NSSet *filterSet = [NSSet setWithObjects: @"A", @"Z", @"Q",
BOOL (^test)(id obj, NSUInteger idx, BOOL *stop); //Block
declaration returns BOOL, params inc. id and BOOL
//body of block gets the block literal ^(id obj, NSUInteger idx,
Bool *stop)... and the body logic
test = ^ (id obj, NSUInteger idx, BOOL *stop) {
  if (idx & 5) {
  if ([filterSet containsObject: obj]) {
return YES; &
return NO; &
Apple提供的另外一个例子是:&
__block BOOL found = NO; &
NSSet *aSet = [NSSet setWithObjects: @"Alpha", @"Beta",
@"Gamma", @"X", nil]; &
NSString *string = @"gamma"; &
//we provide below a way of how to enumerate, using our own
compare logic &
[aSet enumerateObjectsUsingBlock:^(id obj, BOOL *stop) {
  if ([obj localizedCaseInsensitiveCompare:string] ==
NSOrderedSame) {
  *stop = YES;
  found = YES;
As you can see, it takes a little while to have it sink in but
once you get it, it's quite simple. I suggest looking at Apple's
documentation, as well as looking at the referenced APIs to see how
they are used. Practice makes perfect. &
原文出处:/topic/2281-how-to-use-blocks-with-ios/
objective-c block 详解
Apple 在C, Objective-C, C 加上Block这个延申用法。目前只有Mac 10.6 和iOS
4有支援。Block是由一堆可执行的程式组成,也可以称做没有名字的Function (Anonymous
function)。如果是Mac 10.6 或 iOS 4.0 之前的平台可以利用
/p/plblocks/
这个project得以支援Block语法。&
Apple有一个叫做GCD(Grand Central
Dispach)的新功能,用在同步处理(concurrency)的环境下有更好的效率。Block语法产生的动机就是来自于GCD,用Block包好
一个工作量交给GCD,GCD有一个宏观的视野可以来分配CPU,GPU,Memory的来下最好的决定。
Block 简介&
Block其实行为和Function很像,最大的差别是在可以存取同一个Scope的变数值。&
Block 实体会长成这样&
^(传入参数列行为主体;
Block实体开头是"^",接着是由小括号所包起来的参数列(比如 int a, int b, float
c),行为的主体由大括号包起来,专有名词叫做block
literal。行为主体可以用return回传值,型别会被compiler自动办识出来。如果没有参数列要这样写(void)。&
这是代表Block会回传输入值的平方值(int a 就是参数列,return a*a;
就是行为主体)。记得主体里最后要加";"因为是叙述,而整个{}最后也要要加";"因为Block是个物件实体。&
很怪吧。后面小括号里的5 会被当成a的输入值然后经由Block输出5*5 =
25指定给result这个变数。&
有没有简单一点的方法不然每次都要写这么长?有。接下来要介绍一个叫Block
Pointer的东西来简化我们的写法。&
Block Pointer是这样宣告的&
&回传值 名字参数列;
直接来看一个列子&
// 有一个叫square的Block Pointer,其所指向的Block是有一个int 输入和 int 输出
&square = ^(int a ) {return a*}; // 将刚刚Block
实体指定给 square
使用Block Pointer的例子&
&int result = square(5); //
感觉上不就是funtion的用法吗?
也可以把Block Pointer当成参数传给一个function,比如说&
&void myFuction( int (^mySquare) (int) ); //
function 的宣告,
传入一个有一个int输入和int输出的Block 型别的参数&
呼叫这个myFunction的时候就是这样呼叫&
&int (^mySqaure) (int) = ^(int a) {return
a*a;};// 先给好一个有实体的block pointer叫mySquare myFunction( mySqaure ) ;
//把mySquare这个block pointer给myFunction这个function
或是不用block pointer 直接给一个block 实体,就这样写&
当成Objective-C method
的传入值的话都是要把型别写在变数前面然后加上小括号,因些应该就要这样写&
&-(void) objcMethod:( ) // square
变数的型别是 int (^) (int)
读文至此是不是对Block有基本的认识? 接下来我们要谈谈Block相关的行为和特色&
首先是来看一下在Block里面存取外部变数的方法
1. 可以读取和Block pointer同一个scope的变数值:&
int outA = 8;&
int (^myPtr) (int) = ^(int a) {return outA
// block 里面可以读同一个scope的outA的值&
int result = myPtr(3); // result is 11&
我们再来看一个很有趣的例子 &&
  事实上呢,myPtr在其主体用到outA这个变数值的时候是做了一个copy的动作把outA的值copy下来。所以之后outA即使换了新的值对于myPtr里copy的值是没有影响到的。&
要注意的是,这个指的值是变数的值,如果这个变数的值是一个记忆体的位置,换句话说,这个变数是个pointer的话,它指到的值是可以在block里被改变的。&
  NSMutableArray * mutableArray = [NSMutableArray
arrayWithObjects:@"one",@"two",@"three",nil];&
  int result = ^(int a) { [mutableArray removeLastObject];
return a*a;} (5);&
  NSLog(@"test array %@", mutableArray);&
原本mutableArray的值是{@"one",@"two",@"three"}在block里被更改mutableArray所指向的物件后,mutableArray的值就会被成{@"one",@"two"}&
2. 直接存取static 的变数 &
static int outA = 8;&
int (^myPtr) (int) = ^(int a) {return outA
// block 里面可以读同一个scope的outA的值&
  // 在呼叫myPtr之前改变outA的值&
int result = myPtr(3); // result 的值是,因为outA是个static
变数会直接反应其值&
甚至可以在block里面直接改变outA的值比如这样写&
static int outA = 8;&
int (^myPtr) (int) = ^(int a) { outA= 5; return outA
// block 里面改变outA的值&
int result = myPtr(3); // result 的值是,因为outA是个static
变数会直接反应其值&
3. Block Variable&
在某个变数前面如果加上修饰字__block 的话(注意block前有两个下底线),这个变数又称为block
variable。那么在block里就可以任意修改此变数值,变数值的改变也可以知道。&
因为myPtr和myPtr2都有用到num这个block variable,最后result的值就会是7
生命周期和记忆体管理&
因为block也是继承自NSObject,所以其生命周期和记忆体的管理也就非常之重要。&
block一开始都是被放到stack里,换句话说其生命周期随着method或function结束就会被回收,和一般变数的生命周期一样。&
关于记忆体的管理请遵循这几个要点&
pointer的实体会在method或function结束后就会被清掉&
2. 如果要保存block pointer的实体要用-copy指令,这样block
pointer就会被放到heap里&
  2.1 block 主体里用到的block variable 也会被搬到heap
而有新的记忆体位置,且一并更新有用到这个block variable
的block都指到新的位置&
  2.2 一般的variable值会被copy&
  2.3 如果主体里用到的variable是object的话,此object会被retain, block
release时也会被release&
  2.4 __block variable
里用到的object是不会被retain的&
首先来看一下这个例子 &&
&typedef int
(^MyBlock)(int);&
MyBlock genBlock();&
int main(){&
  MyBlock = genBlock();&
  int result = outBlock(5);&
  NSLog(@"result is %d",[outBlock retainCount] ); //
segmentation fault&
  NSLog(@"result is %d",result );&
  return 0 ;&
MyBlock genBlock() {&
  int a = 3;&
  MyBlock = ^(int n) {&
  return n*a; };    }
此程式由genBlock里产生的block再指定给main
function的outBlock变数,执行这个程式会得到&
Segmentation fault&
(注:有时候把 genBlock里的a
去掉就可以跑出结果的情形,这是系统cache住记忆体,并不是inBlock真得一直存在,久了还是会被回收,千万不要以为是对的写法)&
表示我们用到了不该用的记忆体,在这个例子的情况下是在genBlock里的inBlock变数在return的时候就被回收了,outBlock无法有一个合法的记忆体位置-retainCount就没意义了。&
如果这个时候需要保留inBlock的值就要用-copy指令,将genBlock改成&
这样[inBlock
copy]的回传值就会被放到heap,就可以一直使用(记得要release)&
执行结果是 result is 1 result is 15&
再次提醒要记得release outBlock。&
如果一回传[inBlock copy]的值就不再需要的时候可以这样写&
-copy指令是为了要把block
从stack搬到heap,autorelease是为了平冲retainCount加到autorelease oop
,回传之后等到事件结束就清掉。&
接下来是block存取到的local variable是个物件的型别,然后做copy
&MyBlock genBlock() {&
  int a = 3;&
  NSMutableString * myString = [NSMutableString
  MyBlock inBlock = ^(int n) {&
  NSLog(@"retain count of string %d",[myString
retainCount]);&
  return n*a;&
  return [inBlock copy] ;&
结果会印出&
retain count of string 2&
这个结果和上面2.3提到的一样,local variable被retain了&
那再来试试2.4,在local variable前面加上__block&
  int a = 3;&
  __block NSMutableString * myString = [NSMutableString
  MyBlock inBlock = ^(int n) {&
  NSLog(@"retain count of string %d",[myString
retainCount]);&
  return n*a;&
  return [inBlock copy] ;&
执行的结果就是会&
retain count of string 1
Block Copying注意事项&
如果在Class method里面做copying block动作的话&
1. 在Block里如果有直接存取到self,则self会被retain&
2. 在Block里如果取存到instance variable
(无论直接或是从accessor),则self会被retain&
3. 取存到local
variable所拥有的object时,这个object会被retain&
让我们来看一个自订的Class&
  NSString *&
  void (^myLog) (NSString * deco);&
-(void) logN&
@implementation MyObject&
-(id) initWithTitle:(NSString * )
newTitle{&
  if(self = [super init]){&
  title = newT&
  myLog = [^(NSString * deco) { NSLog(@"%@%@%@",deco, title,
deco );} copy];&
& }    }&
-(void) logName{&
  myLog(@"==");&
-(void ) dealloc{&
  [myLog release]; [title release];&
  [super dealloc];&
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。

我要回帖

更多关于 ios 修改键盘return键 的文章

 

随机推荐