iOS利用block实现链式编程方法

【一】遭遇

到今天iOS开发中最常用的语言还是objc,市场就像泰坦尼克号,人虽然在上楼,但是船在下沉,所以人还是在下沉。虽然swift出现的迅猛,但是大部分开发者面对的还是objc。什么时候swift替代objc,今天的objc开发人员也不用太着急,说不定船都沉了(苹果保佑)。

objc最令人头疼的是他看起来像部落语言一样的表达。比如下面这行新手代码,但是就像求偶讯号一样晦涩:

[[NSMutableDictionary alloc] initWithContentsOfURL:[NSURL URLWithString:@"a.txt"]][@"persons"][12];

但它并没有告诉别人任何有意义的事情,分解一下语法就像下面一样:

NSMutableDictionary* dict = [[NSMutableDictionary alloc] initWithContentsOfURL:[NSURL URLWithString:@"a.txt"]];

NSArray* arr = dict[@"persons"];

arr[12];

语言发展到今天,代码的普世价值不是效率,而是开发效率。这就是为什么java能够成为王者的原因。因为java写起来快,好读。

【二】探索

objc比起java又慢又不好读。那么如何让objc看起来像java一样呢。纵观objc全部语法,只有block能够办到。我们来看block的定义

returnType  (^name)  (val1, val2, ...);

返回类型    变量名        参数列表//我们可以从表面认为他是一根指向函数的指针,这个函数的样子如下(returnType)name(val1, val2, ...)

{//......}

block具有一个函数的外观,又被当作一个变量。那么block就具备两个功能,第一:可以作为类的属性被'点'出来。第二:可以当作函数直接调用。下面逐个解释,第一个类的属性可以点出来,比如person.name;这很好理解,你一定见过,str.length;对吧。第二个呢,block作为一个变量,但是又可以把它当作指向函数的指针一样调用。

NSString*(^myBlock)() = ^(){return@"菊乐"; };//定义一个返回值为NSString类型,无参的,并且名字叫做myBlock的blockmyBlock();//这一行就是调用NSString result= myBlock();//这是取出block执行后拿到的返回值,也就是@"菊乐"

这里再解释一次block的定义:上面的myBlock可以认为是指向一个定义如下的函数的指针,这个函数是

(NSString*) myBlock()

{//...}//指向函数的指针NSString* (*p) ();//可以认为指针p就是myBlock(其实block的真实身份更加复杂)

【三】推理

我们来幻想一下objc写起来是这样的

//设置视图位置和大小,设置视图背景色view.setFrame(0,0,50,50).setBackgroundColor(@"#0c0c0c".toColor() );//移除空格并在控制台打印字诗句@"白 日 依 山 尽 , 黄 河 入 海 流".removeStr(@"").nslog();

而实际上要写5行的代码,一行3秒,3行15秒。就这样错过了一次摇一摇的机会,人生在缓慢的艰难,而我们却还一无所知。

view.frame = CGRectMake(0,0,50,50);

view.backgroundColor= [UIColor colorWithRed:0.5green:0.5blue:0.5alpha:1.0];

NSString* str=@"白 日 依 山 尽 , 黄 河 入 海 流";

str= [str stringByReplacingCharactersInRange:@""withString:@""];

NSLog(str);

现在我们来倒着分析如何使用block来实现链式编程,再来观察这句话:

view.setFrame(0,0,50,50).setBackgroundColor(@"#0c0c0c".toColor() );

其中的setFrame和setBackgroundColor他们是什么?大家一定知道是属性。可是属性是不带括号的,setFrame()他是属性吗?那他又是什么呢?setFrame()是属性,并且是block类型的,因为block可以加括号调用。就像这样调用block();那么还有一个问题很关键:view.setFrame().setBackgroundColor();怎么可以连续点出来,这刚开始很不好理解。这并不难,我们往前看那句话:

NSString result = myBlock();

细心的去发现,block是可以有返回值的,那么我们就依靠这个返回值就可以点出一堆属性,一直点下去,这样我们的链式编程的思路就通了。

【四】实践

我们现在就来实现view.setFrame().setBackgroundColor();

首先准备一个分类。头文件定义如下:

//UIView+Extension.h#import@interfaceUIView(Extesion)@PRoperty (nonatomic,copy) UIView* (^setFrame)(CGFloat x, CGFloat y, CGFloat w, CGFloat h);

@property (nonatomic,copy) UIView* (^setBackgroundColor)(UIColor*color);@end

我们在UIView类上扩展了两个额外属性setFrame和setBackgroundColor,这意味着只要是继承自UIView的对象就可以点出来这两个属性。

现在我们需要理解一下两个的区别:

view.setFrame;//这是获取属性,它返回一个blockview.setFrame();//这是获取属性,它返回一个block,最后我们使用括号调用了这个block,这个block的返回值是UIView类型的对象,那么他就可以继续点出下一个属性了

view.setFrame()这句话的末尾因为加上了括号所以执行了block,而他的返回类型是一个UIView对象,所以可以调用setBackgroundColor();

这里解释一下为什么用copy,block这种类型本来是值类型的,他本来是在栈上的,在ARC环境下如果被任何强指针过了一次,编译器就会把他进行一次copy,放到堆内存中。block的retain行为默认是用copy的行为实现的,因为block变量默认是声明为栈变量的,为了能够在block的声明域外使用应该使用copy。

接下来实现.m文件内的代码:

- (UIView *(^)(CGFloat, CGFloat, CGFloat, CGFloat))setFrame

{return?;

}

不难分析出,这个属性的类型是block,具体是UIView* (^)(CGFloat , CGFloat , CGFloat , CGFloat )类型。那么‘?’就是这样一个类型的对象。可是这个对象从哪里获得呢,如果是个NSString我还存储的有,而这个对象只能无从获取。这并不重要,因为我们并不要要block对象本身,我们需要的是:block对象他能够执行一些功能就够了。所以属性内部返回一个临时block对象,这个block内部呢去执行一些功能,最重要的是block内部一定要返回UIView类型的对象。编译器会对block的类型进行苛刻的检测。

- (UIView *(^)(CGFloat, CGFloat, CGFloat, CGFloat))setFrame

{return^(CGFloat x, CGFloat y, CGFloat w, CGFloat h){//返回临时变量的block

self.frame=CGRectMake(x, y, w, h);//block执行一些功能returnself;//block执行完毕的返回值

};

}

下面是.m文件的实现

//UIView+Extension.m#import"UIView+Extension.h"@implementationUIView(Extesion)- (UIView *(^)(CGFloat, CGFloat, CGFloat, CGFloat))setFrame

{return^(CGFloat x, CGFloat y, CGFloat w, CGFloat h){

self.frame=CGRectMake(x, y, w, h);returnself;

};

}- (void)setSetFrame:(UIView *(^)(CGFloat, CGFloat, CGFloat, CGFloat))setFrame{};//该属性不需要从外部设置,不想报警告就写空方法- (UIView *(^)(UIColor *))setBackgroundColor

{return^(UIColor*color){

self.backgroundColor=color;returnself;

};

}- (void)setSetBackgroundColor:(UIView *(^)(UIColor *))setBackgroundColor{};@end

【五】崩溃

objc中向nil对象发送任何消息都不会崩溃,但是发送他不能处理的消息类型就会崩溃,这也是最经常遇到了情况。还有这样也会崩溃:nil.length; view.length;调用不存在的属性也会崩溃。那么这是我们要处理的一个重要的情况。

试想,一行代码中间突然有一个处理返回了nil给下一个环节,一调用就崩溃,关键是断点并不能明确告诉你在哪一行。我们只能从控制台中获得调试信息。这也是链式编程的弊端之一。

【六】效率

关于效率,肯定比原生低那么一丁点的,几乎可以忽略的,只是多了一次属性调用,一次一临时block的创建,一次block的执行。博主的观点是为了提高开发效率,而降低一些运行效率。有时候也是值得的。最后苹果也是大力提倡我们使用block的。祝愉快。

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

推荐阅读更多精彩内容

  • 前言 Blocks是C语言的扩充功能,而Apple 在OS X Snow Leopard 和 iOS 4中引入了这...
    小人不才阅读 3,766评论 0 23
  • iOS代码块Block 概述 代码块Block是苹果在iOS4开始引入的对C语言的扩展,用来实现匿名函数的特性,B...
    smile刺客阅读 2,344评论 2 26
  • Block使用场景,可以在两个界面的传值,也可以对代码封装作为参数的传递等。用过GCD就知道Block的精妙之处。...
    Coder_JMicheal阅读 723评论 2 1
  • 转至元数据结尾创建: 董潇伟,最新修改于: 十二月 23, 2016 转至元数据起始第一章:isa和Class一....
    40c0490e5268阅读 1,703评论 0 9
  • 最近一段时间,都太过无聊,定好的看书,学习,都被新认识的朋友所打断,也许刚认识,都有一些新鲜感吧,彼此聊了很多,有...
    JING1211阅读 150评论 0 1