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


165

语言规范中所述,可以使用扩展将扩展添加到现有的Swift对象类型。

结果,可以创建扩展,例如:

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

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

过去,惯例是extendedtype+categoryname.m用于Objective-C指南中讨论的Objective-C类型。但是Swift示例没有类别名称,并且调用它String.swift似乎不合适。

所以问题是:给定以上String扩展名,swift源文件应调用什么?


4
这不是一个codereview问题-我不在乎这个特定的示例,我想知道什么是快速命名约定。
AlBlue 2014年

2
没有命名约定。我们唯一需要做的就是来自Objective-C的类别,该类别始终遵循ClassName+ExtensionName格式,而且我认为没有太多人在使用。此外,我发现笨拙地代替仅一起定义类和扩展,或者给文件起一个更好的名称FooAbleTypes,例如在聚合中定义实例。
CodaFi

4
这里没有命名的做法呢。这是一个想法:将所有全局扩展集在一起Extensions.swift。这样,您就不会失去对它们的了解,而新加入代码库的人将立即注意到它们。而且我更希望将一次性扩展名保留在需要它们的文件
Andrew

1
正如安德鲁所说,尚无标准的命名惯例-因此,此问题被要求专门征求意见,以便新成立的社区可以提出一些建议的想法。
AlBlue 2014年

1
在我看来,只有一个extensions.swift文件是可行的方法。使结构内部井井有条(以您自己的方式),轻松找到所需的内容。单个文件很容易从各种项目复制或链接到其他项目,并且不会遗忘任何东西。
Yohst '16

Answers:


202

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

String+UTF8Data.swift

优点是命名约定使您易于理解它是扩展名以及正在扩展哪个Class的名。

使用Extensions.swift甚至使用的问题StringExtensions.swift在于,如果不查看文件内容就无法通过文件名来推断文件的用途。

xxxable.swift对于仅定义方法的协议或扩展,使用Java 使用的方法行之有效。但是同样,上面的示例定义了一个属性,因此在UTF8Dataable.swift语法上没有太多意义。


1
尽管可以推断出命名约定所扩展的内容,但这是IHMO的一种不必要的复杂情况。我保留了一个通常用于每个项目的extensions.swift文件,而不是大量的<name> + <extension> .swift文件。在内部对文件进行组织,以便轻松查找扩展的特定类。
Yohst '16

18
答案<name> + <extension> .swift确实是Xcode在Xcode 8中为Core Data创建NSManagedObject子类时的方式。
杰里·克里诺克

4
如果扩展实现多种方法怎么办?
AlexVPerl

2
尽可能做到描述性。例如,如果您具有Image的扩展名,其中包括应用滤镜的不同功能,则将其命名为Image + Filters.swift。可以对扩展功能的相关组使用不同的文件。将相关的事物分组在一起,但将无关的事物分开。生活会很好。
picciano '17

如果您使用的约定ExtendedType+Functionality.swift,是否将所有String扩展名排序到例如该文件夹下各自的子文件夹(即StringString Extensions)中是一种好习惯Extensions?还是只将所有扩展文件存储在同一级别的Extensions文件夹下更好?
Noah Wilder

8

没有Swift约定。把事情简单化:

StringExtensions.swift

我为要扩展的每个类创建一个文件。如果您对所有扩展名使用单个文件,它将很快变成丛林。


8
这似乎不是特别可重用。
凯勒

1
相比于?
Mike Taverne

3
与用于单个(或明确相关)目的的类扩展的文件(或紧密耦合的文件)相比。听起来像“ StringExtensions”之类的东西可能包含从通用字符串清理到特定于应用程序的逻辑的所有内容,如果考虑到重用,这可能不是最佳方法。可可命名惯例倾向于功能而不是实现。我认为“ StringExtensions”表示后者。除了命名约定之外,我当然更喜欢在ObjC中接受的答案,但是在Swift中,由于模块的原因,这似乎是一种更好的方法。
凯勒

2
这就说得通了。我更多地考虑的是单个应用程序,而不在乎重用。例如,假设我有一些不相关的字符串函数要用作扩展名-我可以创建一个文件并将所有这些函数放在此处,或者为每个函数创建一个文件。我喜欢那种情况下单个文件的简单性。但是你的推理是正确的。谢谢。
Mike Taverne

这是完全有道理的,前提是此处添加的内容自然适用于所有字符串(例如,“ trimRight()”)。如果它是特定于用例的东西(即'formatAccountNumber()'),则文件应为'Strings + AccountFormatting.swift',并且应将其范围限定在仅实际使用的位置,以免造成混乱。其他地方的“字符串”表面API。
Mark A. Donohoe

1

StringExtensions.swift在添加过多内容以将文件拆分为诸如String+utf8Data.swift和之前,我更喜欢String+Encrypt.swift

还有一件事,将相似的文件合并为一个文件,将使您的构建更快。请参阅优化快速构建时间


1
同一件事有两个文件命名约定。我认为那很糟糕。
含义-

@含义-这取决于。两种命名约定都是众所周知的,并且由Apple Documents推荐。你爱怎么做就怎么做。
DawnSong

我希望更多的程序员通过限制命名和代码(格式)变化来追求优雅。
含义-

@意义事项优雅有两个方面,就像一个经典的有争议的问题,即如何用类C语言编写花括号。这是微不足道的,所以我认为没有必要选择一个并使其成为强制性的方法,直到大多数人同意这样做为止。
DawnSong

我的意思是一致性的优雅:使用一种方式来命名扩展名,或使用一种方式来放置花括号。然后,我认为不同花括号样式的可读性存在可测量的差异;所以我根本不认为这是“琐碎的”。
含义-

0

如果您有一组团队同意的通用和其他增强功能,请将它们作为Extensions.swift合并在一起,作为Keep-It-Simple一级解决方案。但是,随着您的复杂性增加,或者扩展变得越来越复杂,需要一个层次结构来封装复杂性。在这种情况下,我将以示例的方式推荐以下做法。

我有一堂课,与我的后端对话,叫做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),但是就我看来,就隔离接口而言,这是一个干净的解决方案。

我认为这种方法对于外部指定的类以及您自己的类都同样有效。


0

为什么还要辩论?我是否应该将所有子类放入一个名为_Subclasses.swift的文件中。我觉得不是。Swift具有基于模块的名称间隔。扩展一个众所周知的Swift类需要一个特定于其目的的文件。我可能会有一个大团队来创建一个UIViewExtensions.swift文件,该文件没有任何目的,并且会使开发人员感到困惑,并且很容易在无法构建的项目中进行复制。Objective-C命名约定可以正常工作,并且在Swift拥有真实姓名间隔之前,这是最好的选择。


就我而言,我认为拥有一个名为UIViewExtensions.swift的文件是很有意义的,只要该文件中定义的扩展名对任何/所有UIView类都有意义,例如“ placeIn(UIView)”方法。如果它是特定于用途的(即,仅针对应用程序的一部分,例如围绕自定义视图装饰,那么我会做UIView + CustomDecoration.swift。要点是,在进行泛化之前,例如说一个名为'UIViewExtensions的文件,您必须考虑使用情况“ .swift不表达任何目的”,当目的是所有UIView的通用扩展名时
Mark A. Donohoe

0

与其在整个地方添加我的评论,不如在一个答案中显示所有评论。

就我个人而言,我采用了一种混合方法,既提供了良好的可用性,又提供了清晰度,同时也不会弄乱我要扩展的对象的API表面积。

例如,任何有意义的可用于任何字符串的东西都将输入StringExtensions.swift诸如trimRight()removeBlankLines()

但是,如果我有一个扩展功能,例如formatAsAccountNumber()不会在该文件中,因为“帐户号”并不是自然适用于任何/所有字符串的内容,并且仅在帐户范围内才有意义。在那种情况下,如果有几种类型/方式实际格式化它,我会创建一个名为Strings+AccountFormatting.swift甚至可能Strings+CustomFormatting.swift带有formatAsAccountNumber()函数的文件。

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


0

我更喜欢用a +强调它包含扩展的事实:

String+Extensions.swift

如果文件太大,则可以出于各种目的将其拆分:

String+UTF8Data.swift

String+Encrypt.swift

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.