iphone 开发 XCode - Blocks 介绍

iphone程序开发 : XCode - Blocks 介绍

Block事实上是一个代码块, 可以将它简单的看作是个函数, 但它能被赋给一个变量. 它在xcode中被描述成  ^ (args...) { expression... }

一个简单的例子:

 

int (^add)(int, int) = ^(int a, int b) { return a + b; };

int x = add(1,2);

 

运行完之后, 变量x的值为 3

有点意思吧, 这个看上去和传统c语言中的函数指针有点类似, 但事实上Block更为灵活. 为什么呢? 细心的人可能会发现,因为Block语句是在一个函数中定义的语句块, 是不是意味着具有和当前函数相同的变量操作的作用域呢? 对,的确如此!

还是看例子吧:

 

int a = 10;
int (^block1)(int) = ^ (int b) { return a + b; };
int x = block1(3);

 

运行之后,变量x的值为 13

可能你会觉得有点晕? 或者你会想问...如果在block 之外对这个变量进行修改了,结果会如何?
让我们稍微修改下以前的代码:

 

int a = 10;
int (^block1)(int) = ^ (int b) { return a + b; };
a = 3;
int x = block1(3);

 

运行后x 的结果依然是 13

事实上,在 Block主体用到这个变量的时候,将做一个copy, 将a当时的值复制下来, 之后a的改动将不再影响到block中的语句的执行了. 如果你用过java, 应该记得如果要在inner函数中使用外部的变量,必须将这个变量加上 final的修饰符,也是类似的道理.

更多的问题又来了. 你会问: 既然是做了个copy,那如果想改变Block外部的变量的值,那不是不可能了么?
对,的确有这个问题,但事实上这套机制没有这么弱智。可以在外部变量前加上一个修饰符 __block, 表示这个变量是一个 block variable. 这样就可以在Block块中任意读写这个变量,而它的数值在外面被改动了也能反映到Block中来。

又是例子:

 

__block int a = 10;
int (^block1)(int) = ^ (int b) { return a + b; };
a = 3;
int x = block1(3);

 

运行后x的值为 6

很有趣吧?

 

其实在ios和apple开发中还是经常能利用这个方便的特性,比如我常爱用blocks方法来实现不同线程中的切换,有些场合要比NSThread和NSOperation灵活些

比如一个异步通信中,控件的属性和方法调用需要在UI线程中(在apple中是主线程)进行,而联网等耗时操作为了不对UI线程造成阻塞,往往需要在另外一个工作线程中运行。

我们可以简单的这么做:

- (IBAction)loginAction:(id)sender {
 NSLog(@"ENTER: onLogin.");

 dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{ // Show the progress bar in the main tread
  dispatch_async(dispatch_get_main_queue(), ^{
   [self.progressControl setMessage:@"通信中,请稍候..."];
   [self.progressControl show];
  });

  // TODO:  connect with server to send login request, then receive response.
  [self loginSuccess];
  
  // Hide the progress bar in the main tread
  dispatch_async(dispatch_get_main_queue(), ^{
   [self.progressControl dismiss];
  });
 });
}

当然你也可以用这么做,这也是较常用的做法

- (IBAction)loginAction:(id)sender {
 NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(doLogin:) object:args];
 [[BFGlobalOperationPool globalInstance]addQueueOperation:operation];
 [operation release];
 
 // Show the progress bar in the main tread
 [self.progressControl setMessage:@"通信中,请稍候..."];
 [self.progressControl show];
}

- (void) doLogin:(id)args {
 // TODO:  connect with server to send login request, then receive response.
 [self loginSuccess];

 // Hide the progress bar in the main tread
 [self.progressControl performSelectorOnMainThread:@selector(dismiss) withObject:nil waitUntilDone:NO];
}

 

显而易见,用blocks的更省事些。



smking:另外, 在ARC的情况下, 如果我们需要修改在block中对某个对象进行操作, 我们需要把这个对象赋值到一个弱引用指针,然后用用这个弱引用指针来进行操作, 或者当外部对这个指针已经释放后,block中仍然会对该指针所指向的地址进行访问,从而会引起崩溃。
如下使用即可:(为了保证这个指针在外部修改后,能反映到这个对象上,所以加上__block修饰词)

    __weak __block HQ_FlashPicImageView *tempSelf =self;


    [UIViewanimateWithDuration:1.0animations:^{

        topFlashImgView.alpha =1.0;

    } completion:^(BOOL finished){

        if (tempSelf.superview == nil) {

            // 表示已经被移除掉了

        }else {

            [tempSelfflashToHide];

        }

    }];



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值