为了简化您的 public-facing API,如果 platform-specific 类型别名是 already-public 类型的别名,您能否将它们设为私有?

To simplify your public-facing API, can you make your platform-specific type aliases private if they alias already-public types?

标题可能看起来有点混乱,但考虑一下这个场景。我们在 UIView 上为 iOS/iPadOS 个应用程序提供了以下扩展。

import UIKit

extension UIView {

    var isVisible:Bool{
        get{ return !isHidden }
        set{ isHidden = !newValue }
    }

    func addSubviews(_ subviews:UIView...) {
        addSubviews(subviews)
    }

    func addSubviews(_ subviews:[UIView]) {
        subviews.forEach{ addSubview([=14=]) }
    }
}

我们在 NSView 上为 macOS 应用程序提供了完全相同的扩展。

import AppKit

extension NSView {

    var isVisible:Bool{
        get{ return !isHidden }
        set{ isHidden = !newValue }
    }

    func addSubviews(_ subviews: NSView...) {
        addSubviews(subviews)
    }

    func addSubviews(_ subviews: [NSView]) {
        subviews.forEach{ addSubview([=15=]) }
    }
}

两者唯一的区别是一个使用UIView,另一个使用NSView.

为了摆脱这种冗余,并避免在任何地方添加平台检查,我们简单地为 class 名称本身设置别名,然后围绕这些别名构建 API,就像这样...


#if os(iOS) || os(tvOS)
    import UIKit
    typealias PlatformView = UIView
#elseif os(OSX)
    import AppKit
    typealias PlatformView = NSView
#endif

extension PlatformView {

    var isVisible:Bool{
        get{ return !isHidden }
        set{ isHidden = !newValue }
    }

    func addSubviews(_ subviews: PlatformView...) {
        addSubviews(subviews)
    }

    func addSubviews(_ subviews:[PlatformView]) {
        subviews.forEach{ addSubview([=16=]) }
    }

问题是我们现在必须公开 PlatformView publicly,这可能会使那些导入我们的 Swift 包的人感到困惑。我们希望他们只会看到 UIViewNSView,具体取决于他们的平台。

所以...是否可以隐藏您的类型别名并公开它们作为别名的 public 类型?

您期望的是预处理器宏的行为。类型别名在编译时被替换为它们的基础类型,这使得它们与它们别名的类型相同。

但是,使用类型别名的接口仍将公开类型别名而不是基础类型,因为类型别名的主要用例之一是提供更有意义(至少在某些上下文中)的名称其他类型或将几种类型(如 typealias ABProtocol = AProtocol & BProtocol)组合成一个名称,因此不公开所述类型别名的接口将带走 typealiases.

的主要用例之一

正如我在回答开头所述,您将使用预处理器宏将您的类型别名替换为 before 编译时间所表示的类型,从而公开public 界面中的别名类型。

然而,遗憾的是 Swift 预处理器宏不如 Obj-C 强大。您不能替换预处理器宏中的类型名称,也不能在预处理器宏中放置类型 declarations/the 打开扩展。

所以没有办法实现既避免代码重复又不得不在 public 接口中公开类型别名的目标。