前置文档/参考资料

download.swift.org/docs/assets…

前言

咱们一般期望对项目里的资源文件(如颜色/图片/字体)有一些函数能提供静态拜访支撑,以此获得 IDE 的上下文自动补全支撑。

最简略的方式是在 UIColor/UIImage/UIFont 等资源类型上直接运用 extension 进行扩展完成,可是这种办法往往会带来命名抵触,导致事务方一起 import 两个基础组件时被逼运用full qualified name来解决,或者有时无法解决,成为编译时错误。

// Module A
extension UIImage { public static var like: UIImage { ... } }
struct Foo {}
// Module B
extension UIImage { public static var like: UIImage { ... } }
struct Foo {}
// Business Module C
import A
import B
UIImage.like // ❌
let a = A.Foo()
let b = B.Foo()
  • ObjectiveC 的思路是经过在命名上参加 namespace 来削减抵触的或许

  • Swift不鼓舞在命名上参加namespace,因此咱们能够经过 namespace 占位Wrapper类型来完成

下面介绍在 西瓜视频 Swift 中常见的几种 namespace 处理办法实践

实践

非 Protocol 类型

✅ 根据协议完成的Wrapper

假如需要在非Protocol类型上添加namespace是能够经过协议承继完成的

public struct XIGWrapper<Base> {
  public let base: Base
  public init(_ base: Base) {
    self.base = base
  }
}
public protocol XIGProtocol {}
public extension XIGProtocol {
  var xig: XIGWrapper<Self> {
    return XIGWrapper(self)
  }
  static var xig: XIGWrapper<Self>.Type {
    return XIGWrapper.self
  }
}

然后比方期望运用 Color.xig.red 和 xxColor.xig.opacity(xx) 就能够写出如下代码

extension Color: XIGProtocol {}
extension XIGWrapper where Base == Color {
  public func opacity(_ value: Double): Color { ... }
  public static var red: Color { ... }
}
// Usage
Color.xig.red
xxColor.xig.opacity(xx)

Protocol 类型

UIKit 框架选用 ObjectiveC + OOP 规划,大部分类型为 NSObject + class

SwiftUI 框架选用 Swift + POP 规划,大部分类型为 struct + protocol

❌ 根据协议完成的Wrapper

可是假如是带 Protocol 类型,如 View 和 ButtonStyle,工作就会有些不太一样

首先咱们无法经过上面的extension办法来完成

extension View: XIGProtocol {} // ❌ Extension of protocol 'View' cannot have an inheritance clause

✅ 根据结构扩展的Wrapper

咱们能够选用另一种方式来进行Wrapper

public struct XIG<Content> {
  let content: Content
  public init(_ content: Content) {
    self.content = content
  }
}
Instance 办法/属性

然后比方期望运用 Text(“xx”).xig.shadowStyle1 就能够写出如下代码

extension View {
  public var xig: XIG<Self> { XIG(self) }
  public static var xig: XIG<Self>.Type { XIG<Self>.self }
}
extension XIG where Content: View {
  public func shddowStyle1() -> some View{
    content.shadow(xx)
  }
}
// Usage
Text("xx").xig.shadowStyle1
Static 办法/属性

可是关于 static 办法推导现在没有找到适宜的办法

传统上不必命名空间咱们是这样编写

extension ButtonStyle where Self == BorderedButtonStyle {
  static var hello: some ButtonStyle { HelloButtonStyle() }
}
struct HelloButtonStyle: ButtonStyle { xx }
// Usage
Text("xx").buttonStyle(.hello)

可是这里咱们仍然会报错

extension XIG where Content == BorderedButtonStyle {
  static func hello: some ButtonStyle { HelloButtonStyle() }
}
struct HelloButtonStyle: ButtonStyle { xx }
// Usage
Text("xx").buttonStyle(.xig.hello) // ❌ Contextual member reference to static property 'xig' requires 'Self' constraint in the protocol extension
Text("xx").buttonStyle(BorderedButtonStyle.xig.hello)
extension XIG where Content: ButtonStyle {
  static func hello: some ButtonStyle { HelloButtonStyle() }
}
struct HelloButtonStyle: ButtonStyle { xx }
// Usage
Text("xx").buttonStyle(.xig.hello) // ❌ Contextual member reference to static property 'xig' requires 'Self' constraint in the protocol extension
Text("xx").buttonStyle(BorderedButtonStyle.xig.hello)

一种临时解决方案

public struct XIGStatic<Content> {
    public init(_ content: Content.Type) {}
}
extension SwiftUI.ButtonStyle {
    public static var xig: XIGStatic<Self> { XIGStatic(Self.self) }
}
// Usage
public struct AnyButtonStyle: ButtonStyle {
    public func makeBody(configuration: Configuration) -> some View { ... } // Unimplement
}
extension ButtonStyle where Self == AnyButtonStyle {
    public static var xig: XIGStatic<AnyButtonStyle> { XIGStatic(AnyButtonStyle.self) }
}
struct HelloButtonStyle: ButtonStyle { ... }
extension XIGStatic where Content == AnyButtonStyle {
    var hello: some ButtonStyle { HelloButtonStyle() }
}
// Then we could final use the following code in business code 
Text("Hello").buttonStyle(.xig.hello) // 

论坛讨论贴:
forums.swift.org/t/namespace…