被滥用的category

objc的最大一个特性就是动态性,利用动态特性,我们可以做很多事情,包括对已有的类和对象添加替换方面属性。但是这也给我们带来了一些隐藏的风险,以及让人很不愉快的一些体验。

绝对不能做的事情

假如我们定义一个category,如下面:

@interface UIView (My)
@end

@implementation UIView (My)
- (void)setFrame:(CGRect)frame {

}
@end

那么会发生什么事情?

系统方法会被替换。这是什么原因呢?是因为主类被先加载,然后才会去加载category,然后会导致原来的方法被替换。

那么我们是不是可以利用这种特性来屏蔽一些我们不能修改的类的方法呢?答案是绝对不能这么做。首先,我们替换了方法,可能会导致一些未知的问题。其次,这种替换是不能保证顺序的,在另一个地方也做了这样的处理,我们无法预知最后是哪一个方法。

所以我们绝对不能使用category来替换原有的方法,真的要替换可以使用method_exchange。

隐藏的风险

有些时候在使用category给第三方类增加方法时,也有可能不小心替换了原有的私有方法,从而导致了一些未知的问题。所以也就是为什么大家提倡在方法名前面增加扩展,以最大可能的避免重名。

理解性下降

越多的扩展就会引入越多的概念,很多api并非系统api,可能会产生一些意义相近,但是有细微区别的情况,这些都会对我们的理解产生不好的影响。

当我们大量引入这类文件的时候,会产生一大串扩展的方法。特别是当我们把这类util方法作为pch文件全局引入的时候。

性能降低

越多的category,会让一个类的方法变多,使方法调用所产生开销也会越大,缓存命中失效的概率也会变大。虽然这些多余的开销微不足道,但是在比较常用的对象上,比如UIView,就会累积。当然这些性能都不是问题。

丑陋的api

方法名前加前缀的确是一种解决方案,至少尽可能的减少了冲突的可能,但并不代表不会冲突。

然而这种api却是极其丑陋。

- (id)my_property;
- (void)my_setProperty;

同时这种api使用KeyPath也会非常的麻烦。

甚至可能会出现这样的情况,大家都为同一个功能添加了一个方法:

- (CGFloat)my_height;
- (CGFloat)daniel_height;
- (CGFloat)jack_height;

改善

那么我们就要讨论如何改善这种情况了。

第三方帮助类

这种方式可以说是最优雅的,虽然有点破坏面向对象。

其中系统就提供了几种关于frame的帮助方法:

CGRectGetHeight()
CGRectGetMaxY()

其中React Native中应用了比较多的转换类:

[Convert stringValue:obj];
[Convert integerValue:obj];

这样就避免了在原有类中添加方法了。实际情况是,很多场景我们也不应该把这些方法加入到扩展中,因为从逻辑上来说,某些方法也不应该出现在这个类中,我们不要单纯的因为方便给一个内容引入太多概念。

属性扩展

另一种方式是通过第三方对象转换到自身的方法。比如上面height属性可以改为:

view.my.height
view.daniel.height
view.jack.height

这样也会带来一些优点,比如可以按照功能设计不同的第三方对象:

obj.convertor.stringValue()
obj.builder.string(@"a").integer(1)

同时这样做还有一个好处就是可以动态的替换第三方转换对象,从而实现更灵活的控制:

protocol Convertable {
  stringValue()
}

date.convertor.stringValue()

只要我们把上面的convertor替换掉,就可以更换时间的format方式了。

这样做的缺点是增加了一个对象的生成,但这并不会产生太多的负面影响。

保持私有化

如果你真的需要使用扩展方法,那么尽量的保持这类方法的私有化,特别是对一些第三方库来说。

然后通过import来部分载入我们所需要的方法。如果一开始就让这些方法暴露在外,那么会形成比较恶性的情况。

比如我们在NSObject上添加了一个关于model的方法,然而我们在UIView上也将会看到,并可以使用了,我们需要尽量去避免这样的设计。

最后

说了这么多,是想建议第三方库的作者不要仅仅为了方便从而滥用category,好好的思考如何才能更好的表达意义。

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

推荐阅读更多精彩内容

  • *面试心声:其实这些题本人都没怎么背,但是在上海 两周半 面了大约10家 收到差不多3个offer,总结起来就是把...
    Dove_iOS阅读 27,139评论 30 470
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,102评论 4 62
  • 从开始的天天发文,到现在自己也记不清多久没发感想。自己思想懒惰了很久,也放松了自己,很久不用心读书了。 今天看到,...
    小溪终入海阅读 248评论 0 7
  • 对于穷孩子来讲,不能靠父母,只能靠自己。没有后门可走,一切全靠自己,想改变命运,就要多读书,知识改变命运。 ...
    求无1824阅读 1,235评论 4 2
  • 你有多久没有看到 满天的繁星城市夜晚虚伪的光明 遮住你的眼睛 每天起早摸黑赶着清晨的早班车上班,望着满是人的车里地...
    夏子轩Well阅读 369评论 0 2