从Objective-C到Swift的过渡

我已经为Objective-C编码了很多年了,对此感到非常满意。 我很高兴将代码放在方括号中。 在Apple在iOS 5.0上引入ARC之前,我什至设法处理了所有我们不得不使用的保留和发布内容。

也许这就是为什么我推迟了我作为Swift开发人员的出场时间。 现在,我们已经将项目迁移到Swift,我看到了这么长时间以来我所缺少的所有收获。 但是,在过渡过程中必须将两种语言结合在一起时,并不是所有事情都变得容易。 这篇文章将涵盖在此过程中做出的一些决定和遇到的问题。

迭代和增量方法

我们的PromoFarma iOS项目是在VIPER架构下使用Objective-C构建的,该项目将所有实现隐藏在协议中,以实现层边界和交互。 有很多资源讨论了干净架构的许多好处,但是我想强调一个: 层隔离

这种层隔离使我们能够逐层计划过渡。 从功能角度来看,一次转换每个图层实际上是一种迭代和增量的方法。 我们能够一次面对一个问题,并且在测试过程中只需进行较少的更改即可测试每个功能。

还应该指出,由于这种方法,我们不断地定期发布版本。

快速发挥潜力:Objective-C合规

为了遵循增量过程,我们将所有层边界协议都保留在Objective-C中 。 这样,所有的Objective-C代码都可以基本保持完整。 当然,这意味着所有新的Swift代码都必须符合Objective-C并必须符合其协议。

因此,第一个Swift实现无法利用其某些功能,例如结构,元组,泛型或高级枚举。 这样做的好处是,它帮助我们遵循了最初的迁移计划。

零或不零

Objective-C中进行编码时,会冒着习惯将nil视为可使用的有效值的风险。 是的,当不应该为nil 值为 nil ,应用程序不会崩溃。 但是,除非您进行处理,否则它也不会按预期工作。

关于Swift的一件好事是,它迫使您在编码时决定一个值是否可以为nil 。 因此,确定所有内容的可空性会使整个迁移比仅将一种语言翻译成另一种语言慢一些。 但是最终,它变成了一个更可靠的应用程序。

再见Mantle和AFNetworking

迁移从实体层开始,因为它是最简单且依赖程度较低的实体 ,这是第一个大问题。 我们使用的是Mantle ,感觉就像将它保留在Swift中就像是逆流而上。

因此,我们决定实施Swift的内置Codable协议,这是第二个大问题。 当我们在数据层中使用AFNetworking时,对可Codable对象进行反序列Codable的过程并不简单。 然后我们尝试了一下,开始使用Alamofire迁移数据层

在中期,这是一个不错的决定,但是迫使我们稍微改变增量方法,并同时迁移实体和数据层 。 它不仅是语言翻译,还必须对每个文件进行一些更改。

扩展…无处不在的扩展

在这两层迁移之后,下一层就很简单了。 不仅因为Presenter,Interactor和Routing层非常简单,而且还因为团队对语言本身有了信心。

值得注意的是,尤其是在Presenter层中 ,我们已经能够按照其所遵循的每个协议在扩展中组织代码,从而提供了很多代码可读性和更好的组织性。

你好泛型

从我作为Android开发人员的经验中,我在Objective-C中一直想念的一件事就是通用类型。 好了,在这里,我们决定在View层中给自己一个项目的第一个礼物。

 类ViewController :UIViewController { 
  var _view:ViewType!  { 
返回视图为? ViewType
}
 覆盖func loadView(){ 
super.loadView()
view = ViewType.self.init()
}
  } 

这是一个非常简单的实现,但是如果我现在还没有的话,那肯定会让我爱上Swift

面向协议的编程

在迁移视图层的一些常见对象时,我们意识到,如果我们使用面向协议的编程(POP)而非面向对象的编程(OOP),则可以明显地优化某些类。 对于一直在OOP中进行编程的人来说,这是一个巨大的范例更改。

Swift协议类似于Objective-C的和Java接口,但是其关键特性是可以使用默认实现对其进行扩展。

我们将在以后的文章中进行更深入的介绍,但是我想提到POP优于OOP的两个主要优点。

首先,没有一种诱惑要创建带有大量方法实现的大型BaseClass ,而大多数子类可能永远不会使用该方法。 而是为每个功能组创建一个协议及其扩展名,并且每个子类型都符合这些协议。

其次,这些协议实现可以通过来自不同层次树的几种类型来遵循。 例如,由于其协议一致性,我们的UICollectionViewCellUITableViewCell子类共享一些实现。

 协议BaseViewCell { 
 静态var cellIdentifier:字符串{get} 
  } 
 扩展名BaseViewCell { 
 静态var cellIdentifier:字符串{ 
返回字符串(描述:类型(of:自我))+“ _ identifier”
}
  } 
  class ItemTableViewCell:UITableViewCell,BaseViewCell { 
  } 
  class ItemCollectionViewCell:UICollectionViewCell,BaseViewCell { 
  } 

删除Objective-C协议继承

迁移完所有层之后,仅保留了旧的Objective-C协议,但仍在处理许多Swift代码。 当我们将它们更改为Swift协议时,我们终于可以摆脱那些丑陋的NSNumberInt32Objective-Cint类型的Swift转换)。 我们还可以通过在单个函数上使用默认属性值来消除一些函数重载。

下一步是什么

现在,整个项目已迁移到Swift ,我们可以开始使用更高级的功能:结构,字符串枚举,计算属性,泛型,闭包,函数编程,协议方向……谁会错过方括号中的代码? 不是我。