点语法,链起来--iOS(Objective-C)链式编程(内有链式文件生成器)

祝福

鸡年到了,祝广大程序猿鸡年大吉。

简介

链式编程,可以使用返回调用者自身来实现。但是有类有很多,每个类也有很多方法,假如要实现链式编程,则需要每一个方法进行命令与实现,工作量之大可想而知。于是乎,笔者就在想如何不用自己写链式实现都可以进行链式编程。

先说用法

步骤1

将该demo的MLCCategory文件夹拖入有新项目。


步骤1.png

导入 #import "NSObject+ChainFileCreater.h"

步骤2

调用方法链式实现文件,把你想进行链式编程的类加进数组,会把该类的没有返回值的实例方法提取出来,包括category�方法

    [NSObject mlc_chainCreateChainFileWithClassNames:
     @[[UIView class],
       [UITextField class],
       [CALayer class],
       [UIButton class],
       [CABasicAnimation class],
       ]];

步骤3

运行项目,看到电脑桌面有个MLChain的文件夹,里面都是你想的链式方法文件,拖进项目

链式文件夹.png

步骤4

开始撸码

简单一点撸

 UIView *view1 = [[UIView alloc] init];
    //创建实例后调用
    view1.mlc_make.backgroundColor([UIColor orangeColor]).
    frame(CGRectMake(50, 100, 100, 100));
    [self.view addSubview:view1];

mlc_make相当于生成一个链式的桥梁对象,所有的方法都经过桥梁对象进行赋值。
另外笔者把setter方法的方法名改成getter的方法进行链式调用

复杂一点撸

    UIView *view2 = UIView.mlc_make
    .backgroundColor([UIColor greenColor])
    .frame_(50, 220, 100, 100)
    .chainObject;
    [self.view addSubview:view2];

与第一个对比,直接使用类创建链式桥梁对象,省却了生成对象的方法。
另外frame_是frame的便利方法,使用宏定义如下

#ifndef frame_             
#define frame_(...)  frame(CGRectMake(__VA_ARGS__))             
#endif

这样省却了CGRectMake的代码。
如果该方法只有一个参数且该参数为常用结构体时,在原链式方法名加下划线(_)的方法生成便利方法。

再再复杂一点撸

 UIButton.mlc_make
    .title_forState(@"button2", UIControlStateNormal)
    .titleColor_forState([UIColor blueColor], UIControlStateNormal)
    .addTarget_action_forEvents(self, @selector(buttonClicked:), UIControlEventTouchUpInside)
    .frame_(170, 220, 100, 100)
    .backgroundColor([UIColor yellowColor])
    .moveToSuperview(self.view);

如果方法有两个或以上参数时,�会使用下划线(_)分割方法名。
moveToSuperview是UIView的category方法,生成链式文件时包括category都会加进来。所以要如果写了新的category方法,需要更新链式方法时,则重新生成链式文件,然后删除有链式文件,最后再拖入链式文件到项目即可。

换个姿势撸

CALayer *layer1 = [CALayer layer];
    [layer1 mlc_makeConfigs:^(MLChain4CALayer *maker) {
        maker.frame_(290, 100, 100, 100);
        maker.backgroundColor([UIColor brownColor].CGColor);
        maker.shadowRadius(20).shadowOff_(50, 50).shadowColor([UIColor blueColor].CGColor).shadowOpacity(1);
        
    }];
    [self.view.layer addSublayer:layer1];

模仿Masonry的设置方式,将要设置的放在block里面设置,按自己的需求将设置分段。

再换一个

CALayer *layer2 =  CALayer.mlc_make
    .frame_(290, 220, 100, 100)
    .backgroundColor([UIColor purpleColor].CGColor)
    .chainObject;
    [self.view.layer addSublayer:layer2];
    
    CABasicAnimation *basicAni = [CABasicAnimation mlc_makeConfigs:^(MLChain4CABasicAnimation *maker) {
        maker.keyPath(@"transform.scale").fromValue(@(0.5)).toValue(@(1.5));
        maker.fillMode(kCAFillModeForwards).autoreverses(YES);
        maker.duration(1).repeatDuration(MAXFLOAT);
    }].chainObject;
    layer2.mlc_make.addAnimation_forKey(basicAni, @"动画");

用类方法调用,使用起来也很方便。

原理

1.如何才能链式编程

链式编程要返回自身,每一个链式方法都必须返回明确的类型才能一直点下去,使用protocol或继承都不行,必须在每一个方法的声明时明确返回对象的类型。所以链式文件中不但有该类的方法声明,也有父类的方法声明。

2.如何使用block对原对象进行设置

为了减少对原类的侵入,使用桥梁类进行设置,对应的代码量的略微增加(生成桥梁对象的代码,即mlc_make)。

参数的入口

首先要制造通用格式的block如下

- (id (^)())testMethod;

乍一看,这是一个不带参数block,其实不然,这是可以让你放肆的block,可以不传参数,也可以传N个参数。详情可见如下链接
objc非主流代码技巧

参数的获得

笔者在所有的链式类中,在+ load方法中对所有链式方法做一个动态添加方法的操作,所有的声明链式方法都走这个方法。

- (instancetype (^)(NSString *selName, ...))mlc_rootChainMethod{
    return ^ id (NSString *selName, ...){
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundeclared-selector"
        id chainObject = [self performSelector:@selector(chainObject)];
#pragma clang diagnostic pop

        NSMethodSignature *sig = [chainObject methodSignatureForSelector:sel_registerName(selName.UTF8String)];
        NSInvocation *inv = [NSInvocation invocationWithMethodSignature:sig];
        [inv setTarget:chainObject];
        [inv setSelector:sel_registerName(selName.UTF8String)];
        va_list args;
        va_start(args, selName);
        [NSObject mlc_setInv:inv withSig:sig andArgs:args];
         va_end(args);
        [inv invoke];
        return self;
    };
}

第一个参数是调用方法的selName,va_list是可变参数列表,只要我们知道下个数据类型,就可以使用va_arg取得下个数据。而数据类型可以从方法的methodSignature取得,然后使用NSInvocation逐一根据数据类型设置。设置的方法setInv:withSig:andArgs:从YYKit中得来。

为了规范传入的值的格式,方便从va_list中取值,带参数的方法都有一个宏,如:

#ifndef alpha                                  
#define alpha(...)  alpha(@"setAlpha:", (double)__VA_ARGS__)                                  
#endif
/**     ClassName-> UIView                                
SEL:   setAlpha: 'd'
     */
- (MLChain4UIView *(^)())alpha;

假如传入int值,取float值,会造成取值不准。为了规避这种情况,需要对传递的参数进行强转成函数所对应的参数类型�。于是笔者使用宏定义的方式,把原selName做为第一个参数,用于va_list查找第一个参数,而后续的参数如果是数值类型,则进行强转再传递。取参数使用到metamacro_at(N, ...)(来自RAC的宏定义),并逐一进行强转。

后语

这是一个链式方法文件的生成器,链式方法使用虽然方便,但是调试起来增加不少难度。平时用于撸demo还是挺爽的。

此处应有demoMLChainDemo

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

推荐阅读更多精彩内容