从接触编程到现在,也接触过很多编程范式,从入门级的面向结构,到现在如日中天的面向对象,还有在web开发中很流行的面向切面的编程思想等。这一次要介绍的主题是:函数式的编程思想。

Native app有很大一部分的时间是在等待事件发生,然后响应事件,比如等待网络请求完成,等待用户的操作,等待某些状态值的改变等等,等这些事件发生后,再做进一步处理。 但是这些等待和响应,并没有一个统一的处理方式。Delegate, Notification, Block, KVO, 常常会不知道该用哪个最合适。

基础中的基础

举个例子最清晰:

a(x) = x*x; b(x) = x+1; a(b(x)) = (x+1)*(x+1)

只要上过初中的都知道,多么简单的一堆函数,其实函数式编程就是这么简单,在IOS中也很容易实现(多亏了block)。先简单介绍下block,一句话总结就是,带有自动变量的匿名函数。

什么是Blocks

Block语法和一般的C语言函数定义只有两点不同:

  1. 没有函数名
  2. 带有^符号
Block类型变量

声明Block变量比较麻烦,所以建议用

typedef int (^blk)(int)

这种来简化声明。

在Block中保存的局部变量是在创建该Block瞬间的局部变量,并且还是常量,所以理论上来说是不能改变它的值的。不过可以通过__block来声明成readwrite,达到改变局部变量的值的效果。

Block注意点

其实Block中保存的是对象的结构体指针,也就是说如果你截获了一个Array对象,你只是往里面添加对象,其实是可以的,而无果是要重新指向另外一个array就crash了,另外,对c语言数组的截获是没有实现的。

一个不使用 block 的理由通常是 block 会存在导致 retain 环 (retain cycles) 的风险。如果发送者需要 retain block 但又不能确保引用在什么时候被赋值为 nil, 那么所有在 block 内对 self 的引用就会发生潜在的 retain 环。

基于Block的FRP

写个最简单的例子:

  • 这是比较普通的实现:

       -(IBAction)showAlertViewPressed:(id)sender {
      UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"test" message:nil delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles: nil];
    
      [alertView show];
    

    }

      -(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
          if (buttonIndex == 0) {
              NSLog(@"Hello");
          }
      }
    
  • 这是基于函数式的:

    -(IBAction)showAlertViewPressed:(id)sender {

      UIAlertView *alertView = [[UIAlertView alloc] initAlertViewWithTitle:@"test" message:nil cancelButtonTitle:@"Cancel" otherButtonTitles: nil onCancelCompletion:^{
          NSLog(@"Hello");
      }];
      [alertView show];
    

    }

这是比较简单的一个例子,不过基本能够感觉出来什么是基于函数式的编程了。

再看一个比较经典的网络请求中的函数式编程:

[[NSURLSession sharedSession] downloadTaskWithURL:url completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{
        //在这里对下载好的数据进行处理

        dispatch_async(dispatch_get_main_queue(), ^{
            //用处理好的数据渲染页面等。
        });
    });

}];

在这里不推荐大家网路请求也在其他线程中,会引发很多问题,比如说线程栈内存耗尽,用系统自带的异步请求就ok了。

新工作初体验

来到同程,也已经一个月了,刚入职还似在眼前,从对整个客户端的一无所知,到现在能够贡献自己的一份力,收获颇丰。在这样一个简单而又不简单的团队中,在这样一种简单的氛围中,对于个人的成长是非常有利的。不得不说,在这样的环境中,能够使人飞速成长,也在这里感谢每一个帮助我,督促我不断前行的每一个人。

再给自己定一个目标,每个月看一本书,无关是否技术类,贵在坚持!

留言

9月 26 2014