为现有对象添加扩展名的Swift文件命名的最佳实践是什么?

可以使用扩展向现有SWIFT对象类型添加扩展,如语言规范中所述。

因此,可以创建扩展,例如:

extension String {
var utf8data:NSData {
return self.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
}
}

但是,对于包含此类扩展名的Swift源文件,最佳命名做法是什么?

过去,对于Objective-C,惯例是使用extendedtype+categoryname.m 类型如Objective-C指南中所述。但Swift示例没有类别名称,将其称为String.swift似乎并不合适。

那么问题来了:给定上述String扩展名,那么SWIFT源文件应该叫什么?

50780 次浏览

我看到的大多数示例都模仿了Objective-C方法。上面的扩展示例是:

String+UTF8Data.swift

这样做的好处是,命名约定使得很容易理解它是一个扩展,以及扩展的是哪个类。

使用Extensions.swift或甚至StringExtensions.swift的问题是,如果不查看文件的内容,就不可能通过文件的名称推断出文件的用途。

对于只定义方法的协议或扩展,使用Java使用的xxxable.swift方法是可行的。但是,上面的例子再次定义了一个属性,因此UTF8Dataable.swift没有太多的语法意义。

没有SWIFT惯例。保持简单:

StringExtensions.swift

我为扩展的每个类创建一个文件。如果你对所有的扩展名都使用一个文件,它很快就会变成一个丛林。

如果您有一套团队认可的通用和杂项增强功能,请将它们作为一个扩展集中在一起。SWIFT作为保持简单的第一级解决方案。然而,随着复杂性的增加,或者扩展变得更加复杂,需要一个层次结构来封装复杂性。在这种情况下,我建议以下做法与一个例子。

我有一个类,它与我的后端进行对话,称为Server。它开始变得越来越大,以覆盖两个不同的目标应用程序。有些人喜欢大文件,但只是在逻辑上与扩展名分开。我的偏好是让每个文件保持相对较短,因此我选择了以下解决方案。Server最初符合CloudAdapterProtocol,并实现了它的所有方法。我所做的是将协议转换为层次结构,使其引用从属协议:

protocol CloudAdapterProtocol: ReggyCloudProtocol, ProReggyCloudProtocol {
var server: CloudServer {
get set
}
func getServerApiVersion(handler: @escaping (String?, Error?) -> Swift.Void)
}

Server.swift中我有

import Foundation
import UIKit
import Alamofire
import AlamofireImage


class Server: CloudAdapterProtocol {
.
.
func getServerApiVersion(handler: @escaping (String?, Error?) -> Swift.Void) {
.
.
}

然后,Server.swift仅实现用于设置服务器和获取API版本的核心服务器API.实际工作分为两个文件:

Server_ReggyCloudProtocol.swift
Server_ProReggyCloudProtocol.swift

它们实现了各自的协议。

这意味着您需要在其他文件中有导入声明(对于本例中的AlamoFire),但在我的视图中,就分离接口而言,这是一个干净的解决方案。

我认为这种方法同样适用于外部指定的类以及您自己的类。

我更喜欢StringExtensions.swift,直到我添加了太多内容,以至于无法将文件拆分为类似String+utf8Data.swiftString+Encrypt.swift的内容。

还有一件事,将类似的文件合并成一个将使您的建筑更快。参见优化快速构建时间

为什么这甚至是一场辩论?我应该把我所有的子类放到一个名为_子类.swift的文件中吗?我认为不应该。Swift具有基于模块的名称间距。要扩展众所周知的Swift类,需要一个特定于其用途的文件。我可以有一个大型团队,创建一个名为UIViewExtensions.swift的文件,该文件没有任何目的,会让开发人员感到困惑,并且很容易在无法构建的项目中复制。Objective-C命名约定工作得很好,在Swift有真正的名称间距之前,这是最好的方法。

而不是到处添加我的评论,我在这里把它们都放在一个答案中。

就我个人而言,我采用了一种混合方法,既能提供良好的可用性和清晰度,又不会使我正在扩展的对象的API表面区域变得混乱。

例如,有道理可用于任何的字符串的任何内容将进入StringExtensions.swift,例如trimRight()removeBlankLines()

但是,如果我有一个扩展函数,如formatAsAccountNumber(),它将进入该文件,因为“帐号”不是自然应用于任何/所有字符串的东西,只有在帐户的上下文中才有意义。在这种情况下,我会创建一个名为Strings+AccountFormatting.swift的文件,或者甚至创建一个名为Strings+CustomFormatting.swift的文件,如果有几种类型/方法可以实际格式化它,则可以使用formatAsAccountNumber()函数。

实际上,在最后一个示例中,我一开始就积极劝阻我的团队不要使用这样的扩展,而是鼓励使用AccountNumberFormatter.format(String)之类的东西,因为它根本不会触及String API表面区域,因为它不应该这样做。例外情况是,如果您在使用该扩展名的同一文件中定义了该扩展名,但无论如何它都不会有自己的文件名。

我更喜欢+,以强调它包含扩展名的事实:

String+Extensions.swift

如果文件变得太大,则可以将其拆分以用于以下用途:

String+UTF8Data.swift

String+Encrypt.swift