【问题标题】:Proper namespacing (or class naming) convention in Swift frameworks (for iOS)Swift 框架中正确的命名空间(或类命名)约定(适用于 iOS)
【发布时间】:2016-10-24 22:18:56
【问题描述】:

TLDR

  1. 如果框架被称为 AEConicalGradient,那么其中的类应该被称为 ConicalGradientLayerConicalGradientView 还是只是 Layer查看

  2. 如果框架被称为 AELog,并且它有一个类也称为 AELog 和其他类称为 Line 有一些委托回调正在使用此 Line 类型,如果您的代码还定义了名为 Line 的类型,如何实现此委托,因为在方法签名 func didLog(line: AELog.Line) 中添加框架名称作为前缀将使错误 'Line' is not a member type of 'AELog' 实际上不是(它是 AELog 框架 的一部分,但它不是其中的 AELog 类 的成员)。

    李>

了解详情

在为 Swift 3 更新我的几个框架时,根据框架名称本身,我对框架类的正确命名约定有很多想法。

最后我意识到我并没有真正在不同的框架中使用相同的约定,所以现在我不喜欢这种缺乏一致性的情况。

我会直接跳到我遇到的一些现实世界的例子:

1.示例:框架没有名为框架名称的类:

框架名为 AEConicalGradient,它由 2 个公共类组成:

  • CALayer 子类
  • UIView 子类

每个类的正确名称应该是什么?

a) AEConicalGradientLayerAEConicalGradientView

b) ConicalGradientLayerConicalGradientView

c) 图层视图

讨论:

a) 我在框架的第一个版本中使用了这个,这两个类都在一个 AEConicalGradient.swift 文件中。我不再喜欢这种方法了,我将源分成多个文件,所以现在我在考虑 b)c) 方法之间。

b) 在这种方法中,我喜欢这样一个事实,即有人可以将这些文件拖到项目中(例如,不使用任何依赖项管理器)或复制/粘贴代码,并且不会过多地丢失上下文(因为清楚名称),但另一方面,如果您将其视为 AEConicalGradient.ConicalGradientLayerAEConicalGradient.ConicalGradientView,这听起来有点重复。

c) AEConicalGradient.LayerAEConicalGradient.View 听起来像我想要的方式,但另一方面,这些更有可能如果有人有自己的 LayerView 类,或者如果他们只是拖动文件或复制/粘贴代码上下文几乎丢失了(比如这是什么Layer 或 View 类?)。

2。示例:框架确实有一个名为框架名称的类:

框架名为 AELog,它由 3 个公共类和一个委托协议组成:

  • 共享实例(及其委托)
  • 原木线模型
  • 配置

讨论:

a) 类似于第一版框架中的第一个示例,我有名为 AELogAELogDelegateAELogLineAELogConfig - 全部在单个 AELog.swift 文件中。

b) 在 Swift 3 的最新更新中,我最终得到了多个文件和类名:AELogAELogDelegateLine配置

那时我意识到,如果你 import AELog 并实现 AELogDelegate(它只有 func didLog(line: Line))并且你已经在你自己的模块中定义了一个不同的 Line它将使只能通过重命名这两个 Line 类之一来解决的冲突!

说实话,我真的不明白如何避免这种情况。因为如果你尝试在像func didLog(line: AELog.Line) 这样的委托方法中输入命名空间,你会得到错误'Line' is not a member type of 'AELog',实际上它不是(它是AELog 框架 的一部分,但它不是 的成员>AELog 类在里面)。

那时我开始对这种“松散”的命名感到有点担心。对这个具体问题有什么建议或意见吗?

c) 本着 1.c) 方法中非常“松散”的命名精神,是否可以将 AELog 类重命名为 LogAELogDelegate 只是 Delegate?这是否会修复 2.b) 中所述的错误,因为没有与框架名称相同的类,所以在这种情况下编译器可能会识别 AELog.Line

问题:
这些方法中的任何一种都有哪些“干净的代码”参数?是否有一个明显的“正确”方法应该如何完成?我在这里遗漏了什么重要的东西吗?

【问题讨论】:

  • 这应该在这里:swift.org/documentation/api-design-guidelines 还有一些关于包管理器的更多信息,您可能需要考虑这些信息。
  • 另外,在类名前加上你的包/库缩写是一个 Objective-C 标准,在 Swift 中是不鼓励的
  • 关于 Swift 命名指南的要点。我在回复中添加了指向它的链接。还链接到关于该主题的 WWDC 演讲,这就是我将这些内容充分内化的地方,以便在下面发布我对这个问题的回复(除了阅读大量源代码之外)。
  • 我觉得有趣的是,如果没有我对 mz2 响应的支持(我仍然觉得它比我的好),投票结果是 4-3。 Swift 是一种有趣的编程语言!我发现关于 API 的 WWDC 演讲也非常好。命名约定似乎仍然有很多“个人”风格。看看 Swift 5.0 的到来应该会很有趣......

标签: swift frameworks coding-style swift3


【解决方案1】:

TL;DR

  1. 类型名称应为 ConicalGradientView 和 ConicalGradientLayer。 “视图”和“层”对于“视图”或“层”概念的描述不够充分。

  2. Swift 编译器无法在该上下文中消除冲突的模块/类型名称的歧义。您将找不到来自 Apple 或第 3 方的代码,这些代码对框架/模块与其中的类型使用冲突名称。这可能是出于技术原因,但它也会令人困惑,而且您将“AELog”作为 Swift 类型名称的情况也不是惯用的。

长答案

类型的名称应该以某种方式 describe its role 在您使用该类型的程序中。虽然这当然是主观的,但我不认为“视图”是视图子类的描述性名称,因为有仅 Cocoa 中就有数十个 NSView / UIView 子类,并且视图在您自己的应用程序中可能实现数百个角色。因此,根据逻辑,仅通过查看该非限定类型名称,您无法真正猜测它的作用,因此它不是一个好名称。模块/命名空间名称的功能更多的是提供最小程度的歧义,从而导致名称冲突的未定义行为(例如,传统上在 C/Objective-C 中不可用的奢侈品),但可以说它的作用不是经常用于完全限定的形式。

还要从“如果我想在我的框架中引入视图的新变体怎么办?”的角度来考虑它。 – 例如,一个专门用于 conical 渐变的单独框架听起来有点好笑。对于具有渐变的不同类型的视图,一个框架听起来像是一个更合理的框架“最小尺寸”(即使您现在可能只实现了一个 conical 案例来满足您的需求) , 这同样适用于像“层”这样的概念。例如,如果“AEGradientView”是您的框架的名称,那么您可以在其中包含诸如 ConicalGradientView、RadialGradientView 等内容,并且可以很好地读出所有内容。最后,如果您希望在使用该框架的 API 时让事情变得更简洁,您可以随时使用typealias

因此,足够的描述性是一个因素,但当然简洁是您要平衡的另一个因素。如果你真的有一个在框架中真正独一无二的类型的案例,并且类型名称可以既简短又清楚地表明它的作用,那么我的约定至少确实是使用最简短的名称。例如,在我共同设计的某个图像数据和元数据处理框架中,Image 是用作图像数据和元数据容器的类型的名称。因为在该框架的术语中确实只有一个类具有“图像”角色,而且至关重要的是,它清楚地描述了该类的用途(与例如“视图”不同)。同样,我为嵌套类型使用尽可能简短的名称,例如用于表示“图像错误”(符合Swift.Error 的枚举)的类型称为Carpaccio.Image.Error

关于您关于模块/类型名称冲突的第二个问题,编译器在该上下文中无法解决这种歧义。您也确实不会在任何 Apple 框架中发现模块和类型名称的任何实例(我也不认为在 3rd 方代码中遇到过任何此类示例)。除了编译器很可能无法消除模块和冲突类名称之间的歧义的技术原因之外,对于遵循平台约定的程序员来说,这也令人困惑:将模块名称视为“产品”的名称和类型inside 作为组成部分——虽然AELog 是 Swift 中日志框架的好名字,但它不是 Swift 代码中类型的惯用名称;像“AE”这样的名称前缀在 Swift 中只是不用于类型——它们甚至对于你在 Swift 中创建的 Objective-C 子类都不是必需的,因为 Objective-C 运行时看到的类的完全限定名实际上包括模块名作为前缀。

今年早些时候在Swift API naming considerations 上也有一个很好的 WWDC 演讲,讨论了上面提到的一些内容。

【讨论】:

    【解决方案2】:

    你无法取悦所有人。记在脑子里。所以问题可能需要是“什么最适合大多数人”?

    (1) “AEConicalGradient.ConicalGradientView”没有冗余。

    (2) 开发人员可以通过多种方式将您的“Layer”类导入他们的项目。您需要确保他们能够在不增加复杂性的情况下完成工作。我会采用最“通用”的导入方式——导入整个框架,而不是单个文件——而不是导入“层”文件。

    (3) 我在显示我的年龄,但没有什么类似于 Xcode 中的“包含”文件。

    从这个开始,我会说在最深层次上尽可能保持通用性 - 制作一个“层”文件和类,如果他们决定让用户进行所需的手动更改以使其成为“AELayer”导入单个文件。毕竟,他们正在抓取一个文件,对吧?

    所以我对层次结构的选择是:

    AE框架

    规范

    图层

    查看

    日志

    委托

    线

    配置

    您可以选择各个文件中需要包含的内容。这是我建议的框架设置:

    文件“AEFramework.swift”(这也是你的目标):

    public class Canonical {
    
    }
    

    文件“Canonical.swift”:

    extension Canonical {
        public class View: UIView {
    
        }
        public class Layer: CALayer {
    
        }
    }
    

    文件“Layer.swift”:

    extension Canoncial.Layer {
    
    }
    

    使用事物最简单的方法是:

    import AEFramework
    let myLayer = Canoncial.Layer()
    

    最复杂的方法是在将“Layer.swift”添加到您的项目后对其进行更改:

    extension CALayer {
    
    }
    

    【讨论】:

      猜你喜欢
      • 2016-03-25
      • 2023-03-03
      • 1970-01-01
      • 2015-03-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-05
      • 1970-01-01
      相关资源
      最近更新 更多