【问题标题】:Using 'self' in class extension functions in Swift在 Swift 的类扩展函数中使用“self”
【发布时间】:2015-07-01 15:25:24
【问题描述】:

我希望能够从 Nib 中提取 UIView 子类的实例。

我希望能够调用 MyCustomView.instantiateFromNib() 并拥有一个 MyCustomView 实例。我几乎准备好通过桥接头移植我拥有的工作 Objective-C 代码,但我想我会先尝试惯用的方法。那是两个小时前的事了。

extension UIView {
    class func instantiateFromNib() -> Self? {

        let topLevelObjects = NSBundle.mainBundle().loadNibNamed("CustomViews", owner: nil, options: nil)

        for topLevelObject in topLevelObjects {
            if (topLevelObject is self) {
                return topLevelObject
            }
        }

        return nil
    }
}

现在if (topLevelObject is self) { 是错误的,因为“'is' 之后的预期类型”。之后我的尝试显示了很多关于我对 Swift 类型系统的不了解的地方。

  • if (topLevelObject is Self) {
  • if (topLevelObject is self.dynamicType) {
  • if (topLevelObject is self.self) {
  • 一百万个其他变体是not even wrong

感谢任何见解。

【问题讨论】:

    标签: swift


    【解决方案1】:

    使用How can I create instances of managed object subclasses in a NSManagedObject Swift extension?的方法 你可以定义一个通用的辅助方法,从调用上下文中推断self 的类型:

    extension UIView {
    
        class func instantiateFromNib() -> Self? {
            return instantiateFromNibHelper()
        }
    
        private class func instantiateFromNibHelper<T>() -> T? {
            let topLevelObjects = NSBundle.mainBundle().loadNibNamed("CustomViews", owner: nil, options: nil)
    
            for topLevelObject in topLevelObjects {
                if let object = topLevelObject as? T {
                    return object
                }
            }
            return nil
        }
    }
    

    这在我的快速测试中按预期编译和工作。如果 MyCustomView 是你的 UIView 子类

    if let customView = MyCustomView.instantiateFromNib() {
        // `customView` is a `MyCustomView`
        // ...
    } else {
        // Not found in Nib file
    }
    

    给你一个MyCustomView的实例,类型是 自动推断。


    Swift 3 更新:

    extension UIView {
    
        class func instantiateFromNib() -> Self? {
            return instantiateFromNibHelper()
        }
    
        private class func instantiateFromNibHelper<T>() -> T? {
            if let topLevelObjects = Bundle.main.loadNibNamed("CustomViews", owner: nil, options: nil) {
                for topLevelObject in topLevelObjects {
                    if let object = topLevelObject as? T {
                        return object
                    }
                }
            }
            return nil
        }
    }
    

    【讨论】:

    • 太棒了!我曾用通用方法尝试解决这个问题,但惨遭失败。谢谢!
    • 我发现了一个奇怪的错误,如果通过开发提供它可以在模拟器和设备上工作,但在空中它不使用在 Nib 中指定的视图类。我收到崩溃报告,返回另一个类型的另一个视图,我将其视为预期类型。奇怪。
    • 将发布版本的优化级别标志切换为无工作。现在我要弄清楚如何正确修复它。
    • 谢谢。我在这里stackoverflow.com/a/43397745/8047 复制了这种方法,它可以工作。但是,对于数组:我无法让它在外部方法中为 [Self] 工作。有什么提示吗?错误是'Self' is only available in a protocol or as the result of a method in a class; did you mean 'NSManagedObject'?
    【解决方案2】:

    我相信您正在寻找的条件表达式是topLevelObject.dynamicType == self

    结合unsafeBitCast(which, by Apple's own documentation, "Breaks the guarantees of Swift's type system"),我们可以强制将topLevelObject向下转换为self的类型。这应该是安全的,因为我们已经确定 topLevelObjectself 的类型相同

    这是使用 Martin R 描述的泛型绕过辅助方法的一种方法。

    extension UIView {
        class func instantiateFromNib() -> Self? {
    
            let bundle = NSBundle.mainBundle().loadNibNamed("CustomViews", owner: nil, options: nil)
    
            for topLevelObject in topLevelObjects {
                if topLevelObject.dynamicType == self {
                    return unsafeBitCast(topLevelObject, self)
                }
            }
            return nil
        }
    }
    

    请注意,Apple 在他们的文档中也提到了unsafeBitCast

    几乎总是有更好的方法来做任何事情。

    所以要小心!

    【讨论】:

      猜你喜欢
      • 2017-04-24
      • 1970-01-01
      • 2021-09-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多