OC工程下合理使用Swift为.m文件减负

一、文章背景

Swift ABI在5.0版本以后已经趋于稳定,可是公司现有工程还是以OC为主,直接将OC工程改写为Swift工程,无论从工作量还是实用性上来说都是不合理的。所以最佳方式还是混编。但是既然用到了Swift,就要把其优势体现出来。本文主要将得是利用Swift不同于OC独特的扩展功能来为OC的.m文件减负。

二、OC与Swift的扩展的区别

上面提到了本文主要利用Swift的扩展优势来优化OC工程代码,那么我们知道OC本身也有扩展,势必要比较一下两者的区别了。

  • OC扩展

.m文件顶端一般会有一段这样的代码

@interface 类名 ()
    
@end

这个最常见的代码实际上就是OC的一个私有扩展。 一般在这个私有扩展处添加私有成员变量、属性、声明方法等。
OC也可以创建一个公开的扩展文件,相信大家都会操作,这里就不演示了。同样其可以声明属性,方法等,但是扩展文件只有.h声明文件,没有.m实现文件。因为OC扩展的局限性,平常使用的确实很少。我总结的只有在SDK开发的时候,OC扩展的一个实用之处。

OC扩展的优势:
在SDK开发的时候,如果有需要其他内部类需要调用或使用的方法或属性,但是不想对SDK的使用者暴露,可以将这些方法或属性放置到其扩展中。打包SDK前,将扩展文件排为SDK的私有文件中

  • Swift扩展

Swift扩展相对于OC的扩展就厉害多了,本文就是使用Swift扩展的优势来优化OC代码的

Swift扩展的优势:

  1. Swift扩展可以把代码进行模块化区分,把功能性相同的代码放到一个扩展中
  2. Swift类的扩展里的方法、属性(一般为计算属性),在外部都可以使用,而且支持被继承
  3. Swift扩展可编写扩展属性或方法的实现功能

三、利用Swift扩展的优势为OC类减负

下面以一个案例来讲解一下用Swift减负的过程,这里就不介绍桥接过程了,如有疑问,可查看OC与Swift混编之桥接文件这篇文章。
我们先来看看未减负时类的代码结构:

原始OC类结构

  • 优先将XLLTestView类中的代理方法减负出去
    新建XLLTestView.swift文件,添加一个遵循collectionView delegate/dataSource等协议的XLLTestView类扩展,实现对应的代理方法。
extension XLLTestView: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout{
    public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 3
    }
    
    public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        let itemHeight = collectionView.frame.size.height
        return CGSize(width: itemHeight * 101 / 125.0, height: itemHeight)
    }
    
    public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        collectionView.register(XLLTestedCollectionViewCell.self, forCellWithReuseIdentifier: "XLLTestedCollectionViewCell")
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "XLLTestedCollectionViewCell", for: indexPath) as! XLLTestedCollectionViewCell
        cell.item = NSString(format: "%zd", (indexPath.item + 1) * 10)
        return cell
    }
}

extension XLLTestedView: 其他协议 {
    //对应的代理方法
    public func xxx() {
    }
}
  • XLLTestView中可脱离的私有方法(这里是将OC类中的控件布局的私有方法)在swift类扩展中实现,并使用@objc关键字
    请忽略swift布局使用了OC的Masnory库~代码显得略屌丝
@objc public extension XLLTestedView {
    //添加遍历构造函数,可选参数是自身参数为XLLTestView对象的尾随闭包,可选调用
    convenience init(with: ((XLLTestView) -> Void)? = nil) {
        self.init()
        with?(self)
    }
    //将OC类中的布局私有方法放入扩展中
    func setupSubviews() {
        self.addSubview(self.titleLabel)
        self.titleLabel.mas_makeConstraints { (make: MASConstraintMaker!) in
            make.top.equalTo()(kAutoSize(size: 20))
            make.centerX.equalTo()(0)
        }
        self.addSubview(self.collectionView)
        self.collectionView.mas_makeConstraints { (make: MASConstraintMaker!) in
            make.top.equalTo()(self.titleLabel.mas_bottom)?.offset()(kAutoSize(size: 35))
            make.left.right()?.equalTo()(0)
            make.width.equalTo()(kScreenWidth)
            make.bottom.equalTo()(kAutoSize(size: -70))
        }
        self.addSubview(self.sureBtn)
        self.sureBtn.mas_makeConstraints { (make: MASConstraintMaker!) in
            make.bottom.equalTo()(kAutoSize(size: -11))
            make.left.equalTo()(kAutoSize(size: 20))
            make.centerX.equalTo()(0)
            make.height.equalTo()(kAutoSize(size: 42))
        }
    }
    //可以增加其他一些OC能够调用的减负方法..
    func xxx() {
    }
}
  • 将隶属于XLLTestView的专用UI类XLLTestColectionViewCell放入Swift文件中实现
@objc class XLLTestCollectionViewCell: UICollectionViewCell {
    //MARK: life circle
    override init(frame: CGRect) {
        super.init(frame: frame)
        self.setupSubviews()
    }
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    //MARK: private methods
    ...
    // MARK: setter
    ...
    //MARK:destruction methods
    ...
    //MARK: lazy loading
    ...
}
  • 将OC类中的一些@dynamic修饰的属性,需手动实现setter和getter方法,转为Swift的计算属性实现。
    原OC类@dynamic属性及实现
@property (nonatomic, copy, readonly) NSString *myInfo;

@dynamic myInfo;
- (NSString *)myInfo
{
    return @"CoderXLL";
}

将其转化至swift计算属性实现

@objc public extension XLLTestView {
    var myInfo: NSString {
        get {
            return "CoderXLL"
        }
    }
}

至此,基本上完成了对.m文件的减负工作。来看下减负后的代码结构。


减负后的结构

可以看到OC类已经减轻了很多压力,那些对业务逻辑关联不大的代码都已经移到对应的swift文件中去了,使得代码逻辑清晰了不少。

四、总结

其实总体来说代码并没有增多或减少,只是在OC工程下,望着愈渐臃肿的.m文件,这种方式自我感觉可以作为不错的一个应对方案。文章也只是以一个简单的案例进行了抛砖引玉。实际项目中,你肯定也会发现还有更多优化的空间。以上只是我本人的一次实践总结,如果你觉得有什么更好的建议或意见,欢迎留言,共同探讨😝
下面对文章的代码总结的一份demo,感兴趣的可以clone查看
Demo地址

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

推荐阅读更多精彩内容

  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,037评论 1 32
  • 今天又吵架了! 老生常吵的话题:家务,挣钱!您可能要问,这有什么好吵的?且听我慢慢讲来。因为孩子爷爷生...
    wu12阅读 630评论 0 1
  • 刘津是网易高级设计师,北大高材生,然后,即使这样的人在工作中也会遇到苦恼。 最近我开始计划系统的梳理目前的产品:看...
    谷涵先生的小站阅读 1,084评论 0 1
  • 这几天最好的朋友YXY给我说了一堆她们家催婚的事情。其实有时候我常想,为什么她们家一定要把自己女儿往外嫁?不是说女...
    酥酥sususss阅读 398评论 0 1
  • 惰性就如毒瘤,腐蚀性很强。 有时候,复杂的事情简单做,简单的事情重复做,重复的事情坚持做。持续下去,你就是人生赢家...
    寻觅最青春阅读 169评论 0 1