【问题标题】:Cast to typeof(self)转换为 typeof(self)
【发布时间】:2014-08-12 18:08:29
【问题描述】:

是否可以创建一个类别(扩展),最终返回一个转换为instancetype 的对象?我有一个加载 SKS 文件的类别,但由于此类别适用于 SKNode,因此所有其他子类(如 SKSceneSKEmitterNode 等)也将采用它。

所以我只想避免总是从SKNode 转换为instancetype。是否可以将返回类型更改为instancetype 并确保编译器对返回值感到满意?

我想我可以使用-> Self 作为返回类型,但是我不知道如何将scene 转换为instancetype,所以这个东西会编译..

例如:

SKEmitterNode.unarchiveFromFile("Blah") 将返回 SKEmitterNode 的实例

extension SKNode {
    class func unarchiveFromFile(file: String) -> SKNode {
        let path = NSBundle.mainBundle().pathForResource(file, ofType: "sks")
        var sceneData = NSData.dataWithContentsOfFile(path, options: .DataReadingMappedIfSafe, error: nil)

        let unarchiver = NSKeyedUnarchiver(forReadingWithData: sceneData)
        unarchiver.setClass(self.classForKeyedUnarchiver(), forClassName: "SKScene")

        let scene = unarchiver.decodeObjectForKey(NSKeyedArchiveRootObjectKey) as SKNode
        unarchiver.finishDecoding()

        return scene
    }
}

【问题讨论】:

  • 你能把-> SKNode改成-> Selfas SKNode改成as Self吗?
  • 我可以在定义中将 SKNode 更改为 Self,但最后我不能将 scene 转换为 Self。您可能对 objc 中的 instancetype 有同样的问题 :)
  • 对;在 Objective-C 中,您可以在类方法中使用 self,或在实例方法中使用 [self class]

标签: swift


【解决方案1】:

这可能对你有用。我无法测试它,因为我没有太多经验 精灵套件。但它确实编译并且编译器推断类型为

let e = SKEmitterNode.unarchiveFromFile("Blah")

是 SKEmitterNode。这个想法是定义一个通用的辅助函数

func unarchiveFromFileHelper<T where T : SKNode>(file: String) -> T 

这样

class func unarchiveFromFile(file: String) -> Self {
    // define helper function ...
    return unarchiveFromFileHelper(file)
}

使用T == Self 调用辅助函数。

extension SKNode {
    class func unarchiveFromFile(file: String) -> Self {

        func unarchiveFromFileHelper<T where T : SKNode>(file: String) -> T {
            let path = NSBundle.mainBundle().pathForResource(file, ofType: "sks")
            var sceneData = NSData.dataWithContentsOfFile(path, options: .DataReadingMappedIfSafe, error: nil)

            let unarchiver = NSKeyedUnarchiver(forReadingWithData: sceneData)
            unarchiver.setClass(T.classForKeyedUnarchiver(), forClassName: "SKScene")

            let scene = unarchiver.decodeObjectForKey(NSKeyedArchiveRootObjectKey) as T
            unarchiver.finishDecoding()
            return scene
        }

        return unarchiveFromFileHelper(file)
    }
}

更新:如果您的目标是 iOS 8/OS X 10.10 或更高版本 不再需要自定义取消归档方法。如中所述 Cannot use unarchiveFromFile to set GameScene in SpriteKit,可以使用

convenience init?(fileNamed filename: String)

来自SKNode 超类,例如

if let e = SKEmitterNode(fileNamed: "Blah") {
    // ...
}

【讨论】:

  • 虽然这段代码是有效的,但 Swift 编译器只是在发布版本中因 seg 错误而崩溃 :)
  • 但是将内部函数移到外部作为私有类函数可以解决问题。
猜你喜欢
  • 2017-08-12
  • 2015-08-06
  • 1970-01-01
  • 2013-09-16
  • 2020-02-05
  • 1970-01-01
  • 2022-08-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多