如何在iOS中使用Block

 我来答
huanglenzhi
2015-01-16 · 知道合伙人数码行家
huanglenzhi
知道合伙人数码行家
采纳数:117538 获赞数:517191
长期从事计算机组装,维护,网络组建及管理。对计算机硬件、操作系统安装、典型网络设备具有详细认知。

向TA提问 私信TA
展开全部
  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 distance;
  };

  你也可以传入一个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;
  }
  }];
  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.

  

  原文出处:http://answers.oreilly.com/topic/2281-how-to-use-blocks-with-ios/

  

  objective-c block 详解

  Block
  
  Apple 在C, Objective-C, C++加上Block这个延申用法。目前只有Mac 10.6 和iOS 4有支援。Block是由一堆可执行的程式组成,也可以称做没有名字的Function (Anonymous function)。如果是Mac 10.6 或 iOS 4.0 之前的平台可以利用 http://code.google.com/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)。
  看个列子

  ^(int a) {return a*a;};
  这是代表Block会回传输入值的平方值(int a 就是参数列,return a*a; 就是行为主体)。记得主体里最後要加";"因为是叙述,而整个{}最後也要要加";"因为Block是个物件实体。
  用法就是

  int result = ^(int a) {return a*a;} (5);
  很怪吧。後面小括号里的5 会被当成a的输入值然後经由Block输出5*5 = 25指定给result这个变数。
  有没有简单一点的方法不然每次都要写这麼长?有。接下来要介绍一个叫Block Pointer的东西来简化我们的写法。
  Block Pointer是这样宣告的

  回传值 (^名字) (参数列);

  直接来看一个列子

  int (^square) (int);
  // 有一个叫square的Block Pointer,其所指向的Block是有一个int 输入和 int 输出

  square = ^(int a ) {return a*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 实体,就这样写

  myFunction( ^(int a) {return a*a} ) ;
  当成Objective-C method 的传入值的话都是要把型别写在变数前面然後加上小括号,因些应该就要这样写

  -(void) objcMethod:( int (^) (int) ) square; // square 变数的型别是 int (^) (int)
  读文至此是不是对Block有基本的认识? 接下来我们要谈谈Block相关的行为和特色
  首先是来看一下在Block里面存取外部变数的方法

  存取变数
  1. 可以读取和Block pointer同一个scope的变数值:

  {
  int outA = 8;
  int (^myPtr) (int) = ^(int a) {return outA+a;};
  // block 里面可以读同一个scope的outA的值
  int result = myPtr(3); // result is 11
  }
  我们再来看一个很有趣的例子

  {
  int outA = 8;
  int (^myPtr) (int) = ^(int a) {return outA+a;};
  // block 里面可以读同一个scope的outA的值
  outA = 5; // 在呼叫myPtr之前改变outA的值
  int result = myPtr(3); // result 的值还是 11并不是 8
  }
  事实上呢,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"}
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
Storm代理
2023-07-25 广告
StormProxies是一家可靠的代理服务提供商,提供原生IP(住宅原生IP)和高匿名代理服务。以下是关于StormProxies的原生IP服务的一些信息:1. 住宅原生IP:StormProxies提供的住宅原生IP是指从真实的家庭或企... 点击进入详情页
本回答由Storm代理提供
推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式