【问题标题】:How to write a generic Swift class function to initialize classes using a closure?如何编写一个通用的 Swift 类函数来使用闭包初始化类?
【发布时间】:2019-10-21 06:25:31
【问题描述】:

我正在尝试为 Swift 类编写一个通用类函数,它允许我使用尾随闭包语法初始化类。

我已经让它适用于特定的类,例如 UILabel。

// Extension for UILabel
extension UILabel {
    class func new(_ initialization: (inout UILabel) -> Void) -> UILabel {
        var label = UILabel()
        initialization(&label)
        return label
    }
}

// Initialize new UILabel using trailing closure syntax and "new" function
let label = UILabel.new {
    $0.textColor = .red
}

但是,我希望 NSObject 的所有子类都具有此功能,因此我尝试实现上述“新”功能的通用版本。到目前为止,我想出了这个:

extension NSObject {
    class func new(_ initialization: (inout Self) -> Void) -> Self {
        var newSelf = Self()
        initialization(&newSelf)
        return newSelf
    }
}

但这会产生以下错误: 'Self' 仅在协议中可用或作为类中方法的结果;你的意思是“NSObject”吗?

我正在使用 Swift 5.1(Xcode 11 beta)的操场上尝试这个。

【问题讨论】:

  • 这行不通,因为NSObject 的子类可以将init 方法标记为NS_UNAVAILABLE。因此,仅仅因为您有一个扩展 NSObject 的类的元类型对象,并不意味着您可以构造该类型的新对象。
  • 那么只为 UIView 子类做呢?这可能吗?
  • 我会考虑只定义类似func with<T>(_ x: T, body: (inout T) throws -> Void) rethrows -> T { var x = x; try body(&x); return x } 的东西。然后你可以说let label = with(UILabel()) { ... }。然后,您还可以灵活地使用所需的任何初始化程序。

标签: swift generics self initializer


【解决方案1】:

正如 Hamish 所说,也许最好将 init 留在外面,这样它更灵活。但是,可能有一种使用协议的解决方法。

protocol Initializable {
    init()
}

extension Initializable {
    static func new(_ initialization: (inout Self) -> Void) -> Self {
        var newSelf = Self()
        initialization(&newSelf)
        return newSelf
    }
}

extension NSObject: Initializable {}

NSObject 已经有一个init,所以它会自动符合Initializable。 然后在协议上写下你的扩展。

唯一需要注意的是,您现在不能使用 class 修饰符,因为您在 protocol 中。

不确定这是否会导致 NS_UNAVAILABLE 修饰符出现问题,我认为当您在隐藏 init 的类上使用它时,它可能会在运行时崩溃。

【讨论】:

  • 完美,非常感谢,效果很好!当您将它与将init 标记为不可用的子类一起使用时,它确实会在运行时崩溃,但目前还可以。只是出于好奇:那我应该如何理解this proposal?读完这篇文章后,我认为可以在课堂上使用Self,正如我最初的意图。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-27
  • 2021-05-11
  • 2019-01-26
  • 2015-10-10
相关资源
最近更新 更多