Is it possible to make a category (extension) that would eventually return an object casted to instancetype
? I have a category to loads SKS files but since this category is for SKNode
then all other subclasses like SKScene
or SKEmitterNode
, etc.. will adopt it too.
So I would simply like to avoid always casting from SKNode
to instancetype
. Is it possible to change return type to instancetype
and make sure that compiler is happy with return value?
I think I can use -> Self
as return type but then I have no idea how to cast scene
to instancetype so this thing would compile..
For example:
SKEmitterNode.unarchiveFromFile("Blah")
would return an instance of 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
}
}
This might work for you. I could not test it because I have not much experience with SpriteKit. But it does compile and the compiler inferred type for
let e = SKEmitterNode.unarchiveFromFile("Blah")
is SKEmitterNode. The idea is to define a generic helper function
func unarchiveFromFileHelper<T where T : SKNode>(file: String) -> T
so that
class func unarchiveFromFile(file: String) -> Self {
// define helper function ...
return unarchiveFromFileHelper(file)
}
calls the helper function with 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)
}
}
Update: If you are targeting iOS 8/OS X 10.10 or later then there is no need for a custom unarchive method anymore. As noted in Cannot use unarchiveFromFile to set GameScene in SpriteKit, you can use
convenience init?(fileNamed filename: String)
from the SKNode
superclass, e.g.
if let e = SKEmitterNode(fileNamed: "Blah") {
// ...
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With