首页 > 解决方案 > 为了简化面向公众的 API,如果特定于平台的类型别名为已经公开的类型别名,你能否将它们设为私有?

问题描述

标题可能看起来有点混乱,但考虑一下这种情况。我们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($0) }
    }
}

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($0) }
    }
}

两者的唯一区别是一种用途UIView,另一种用途NSView

为了摆脱这种冗余,并避免在任何地方添加平台检查,我们简单地给类名本身加上别名,然后围绕这些别名构建 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($0) }
    }

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

那么......是否可以隐藏您的类型别名并公开它们别名的公共类型?

标签: swiftuikitappkitmultiplatformtype-alias

解决方案


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

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

正如我在回答开头所说的那样,您将编译时使用预处理器宏将您的类型别名替换为表示的类型,从而在您的公共接口中公开别名类型。

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

因此,没有办法实现避免代码重复和必须在公共接口中公开类型别名的目标。


推荐阅读