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

前言

由于“业务”需求,最近我准备复习下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的实践

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容