美文网首页iOS-blockiOS开发ios
浅谈Objective-C中的Block-一个noob的学习小记

浅谈Objective-C中的Block-一个noob的学习小记

作者: cbsfly_ | 来源:发表于2016-01-08 17:23 被阅读460次

    前言

    由于“业务”需求,最近我准备复习下Objective-C中的“块”,也就是大家并不陌生的block,顺便做点小笔记。说实话,其实自己之前对block不是很熟悉,所以这篇文章主要是基础知识,不会涉及太多深层次的东西,个人认为给自己也就是刚接触iOS开发的新手看看还是有作用的。

    理解Block

    在《Learning Cocoa with Objective-C》这本书中说我们可以把block看作是一个变量(variables),但这个变量和一般的变量有一点不同,它不像别的变量可能存储一个整型数或者字符串,它存储的是一段代码。我觉得这个理解很不错,以后我们遇到了block,不妨将block看作一个变量

    如何看懂一个block?

    要读懂,我们首先要会写block。block的声明大致可以分为下面五种形式。

    1.block作为局部变量

    returnType (^blockName)(parameterTypes) = ^returnType(parameters) {code};
    

    这种形式可以看作最基本的block声明形式,最好动手在自己的Xcode中敲一敲。

    2.block作为接口部分属性指令

    @property (nonatomic, copy) returnType (^blockName)(parameterTypes);
    

    3.block作为某个方法的形式参数

    -(void)someMethodThatTakesABlock:(returnType (^)(parameterTypes))blockName;
    

    4.block作为一个被调用的方法

    [someObject someMethodThatTakesABlock:^returnType (parameters) {code}];
    

    5.宏定义

    typedef returnType (^TypeName)(parameterTypes);
    TypeName blockName = ^returnType(parameters) {...};
    

    看完后相信读者和笔者都有一个感觉就是OC中得block非常反人类。但是我们还是可以做一些总结,比如任何情况下block的返回类型都不会单独在一对括号里;block所需要的形参都是单独在括号中的且括号之前没有符号。符号可以说是block的标志,凡是看到^符号就可以认为这是一个block,且括号内的一般式参数类型或者参数名,极少数情况会是block的名字(一般很少情况下会必须给block起名字,所以很多block是没有名字的)。至于block的调用方法是与函数的调用方法一致的。

    这么复杂的定义为何我们还要去学呢?因为block的作用其实非强大。block可以说是OC中实现函数式编程的基础。当我们写一个动画的过程时需要使用block;当我们需要回调网络请求的时候需要block;当我们需要更新UI的时候我们需要block。

    block是如何运行的?

    我们先来看一个简单的demo。

    //声明一个block 
    void (^block)() = ^void (){  //Step.1
        NSLog(@"1");    //Step.3
    };
    //调用block 
    block();        //Step.2
    

    输出很简单就是一个1.为什么要举这个demo呢?我们不妨打个断点来看看。令人惊奇的是,在遇到block的时候我们的代码不是从上往下运行了,当执行到Step.1时函数不再往下执行NSLog方法而是到了Step.2,而Step.2调用了block函数此时才执行块中得NSLog也就是Step.3。

    所以上文就说了,我们应该把block看作是一个变量。当我们定义了一个int x的时候编译程序不会在乎你x的值是什么,而当你要用x做输出或者加减法的时候编译程序才会在内存空间中取出x进行运算。block也是这个道理。

    但我们也不能把Block简单的当做是一个变量,我们来看下一个demo;

    int x = 10;
    
    void (^block)() = ^void (){
        NSLog(@"%d", x);
    };
    
    block();
    x = 11;
    block();
    

    结果两个调用block输出都是10。这就是我们常说的闭包

    在一些语言中,在函数中可以(嵌套)定义另一个函数时,如果内部的函数引用了外部的函数的变量,则可能产生闭包。运行时,一旦外部的 函数被执行,一个闭包就形成了,闭包中包含了内部函数的代码,以及所需外部函数中的变量的引用。

    可以认为,在调用block内部函数时,里面的变量值就是block创建时变量的值。block可以看作是一个封闭的块,一个“不受外界干扰”的块。

    在我们的实际开发中,我们就是要利用block的回调特性和闭包特性。

    block的应用

    1.网络请求

    在网络请求中,block主要是处理网络请求的返回值。一个网络请求不仅有返回数据的情况,也有超时或者链接错误等失败情况,这时我们就需要block。

    [SomeClass getURL:someURL finished:^(NSData * data,NSURLResponse *response,NSError *error) {
            if (error) {
            ...
        }else{
            if (success) {
                ...
            }
        }
    }];
    

    为什么这里要用block呢?这里偷懒引用下美团的原文。(其实是怕我自己的理解有误)

    这里网络请求是异步的,所以当block中代码执行时,getURL:finished:方法调用所在的栈很可能已经不存在了,但是因为回调block和someURL构成了closure,所以即使栈不存在,block仍然可以引用到someURL。

    可能你会说,“我在block中增加一个NSURL类型的参数,把someURL传回来不也可以实现同样的目的吗?”不妨设想如果我们在block中要引用的对象有10个之多,用参数列表传递明显不再现实,用容器类或者专门定义一个类来传递虽然可以,但是前者没有编译器为我们检查错误,后者则相当繁琐。而利用闭包,可以轻易达到灵活性和简洁性的平衡。事实上,美团客户端就大量利用了闭包,在UI层发出请求,在回调中更新某些UI组件。

    而再获取了数据之后,我们还可以直接在块中进行操作,例如更新UI,例如存储model,甚至错误的弹框。

    2.动画

    UIView *ppview = [[UIView alloc] initWithFrame:CGRectMake(0, SCREENHEIGHT/2-50, 50, 50)];
    ppview.backgroundColor = [UIColor yellowColor];
    [self.view addSubview:ppview];
    [UIView animateWithDuration:1.0f animations:^{
        ppview.frame = CGRectMake(SCREENWIDTH, SCREENHEIGHT/2-50, 50, 50);
    } completion:^(BOOL finished) {
        ppview.frame = CGRectMake(SCREENWIDTH/2-25, SCREENHEIGHT/2-50, 50, 50);
    }];
    

    这里为了使代码看起来简洁用了宏定义,所以代码前要加两句话

    #define SCREENWIDTH [UIScreen mainScreen].bounds.size.width
    #define SCREENHEIGHT [UIScreen mainScreen].bounds.size.height
    

    动画的具体效果大家可以自己看,这不是重点。动画部分主要利用了块可以存储代码这一特性,使得动画的代码更简洁易懂。试想若不用block,先不管能不能实现动画效果,每个动画添加一个方法,可能一个简单的动画将有大量的代码。

    总结

    写这篇文章深深感受到自己的基础知识的不够用,其实自己写文的初衷也是想自己踏踏实实的学习iOS开发,写文对知识的总结还是很有效果的。

    由于理解不到位,block的应用那一节可能说的不是很好,希望有错的部分大家一定要帮我指出来,我一定虚心接受。也欢迎来我的博客看看。

    参考文章

    How Do I Declare A Block in Objective-C?

    block在美团iOS的实践

    相关文章

      网友评论

        本文标题:浅谈Objective-C中的Block-一个noob的学习小记

        本文链接:https://www.haomeiwen.com/subject/hcafkttx.html