Вставить в typeof (self)

Можно ли создать категорию (расширение), которая в конечном итоге вернет объект, выделенный в instancetype? У меня есть категория для загрузки файлов SKS, но поскольку эта категория предназначена для SKNode, тогда все остальные подклассы, такие как SKScene или SKEmitterNode и т.д., Тоже будут ее использовать.

Поэтому я просто хотел бы избежать всегда отбрасывания от 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
    }
}

Ответ 1

Это может сработать для вас. Я не мог проверить это, потому что у меня мало опыта с SpriteKit. Но он компилирует и выводит тип компилятора для

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 или более позднюю версию, больше не требуется для пользовательского метода разблокировки. Как отмечено в Нельзя использовать unarchiveFromFile для установки GameScene в SpriteKit, вы можете использовать

convenience init?(fileNamed filename: String)

из суперкласса SKNode, например

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