在 Swift 的类扩展函数中使用“self”

Posted

技术标签:

【中文标题】在 Swift 的类扩展函数中使用“self”【英文标题】:Using 'self' in class extension functions in Swift 【发布时间】: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。

感谢任何见解。

【问题讨论】:

【参考方案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 中指定的视图类。我收到崩溃报告,返回另一个类型的另一个视图,我将其视为预期类型。奇怪。 将发布版本的优化级别标志切换为无工作。现在我要弄清楚如何正确修复它。 谢谢。我在这里***.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

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

所以要小心!

【讨论】:

以上是关于在 Swift 的类扩展函数中使用“self”的主要内容,如果未能解决你的问题,请参考以下文章

在 Swift 中扩展泛型? [复制]

Swift 中带有选择器的协议扩展

swift Swift - UIViewController的类扩展

在本机 safari 应用程序扩展中,我们如何使用 swift 的参数调用 javascript 函数?

Swift 3 中的 NSAttributedString 扩展

UIColor swift 扩展,带有来自 Objective-C 的类访问