Adding NSCoding as an Extension - swift

I'd like to extend a framework class (I don't want to edit the source code directly), and make it conform to NSCoding.
Basically, here's a simplification of the situation I'm in :
/* Can't be edited. */
class Car: NSObject {
var color: String?
}
/* Can be edited */
extension Car: NSCoding {
init(coder aDecoder: NSCoder) {
}
func encodeWithCoder(aCoder: NSCoder) {
}
}
The issue is init(coder aDecoder: NSCoder) is, as per the header file, a designated initializer (isn't this weird though ? shouldn't it be a convenience initializer ?). However, the documentation says extension can't add a new designated initializer.
My English isn't perfect and maybe I missed something out... Or is it really impossible ?

Like the documentation says, extensions can't add new designated initializers. What if there were private properties that need initialization? It would be impossible to properly initialize the type. You can add convenience initializers in an extension because by their nature, they must call a designated initializer.
Also, init(coder aDecoder: NSCoder) is specified to be a designated initializer because it is a whole different route to creating an instance. Take UIViewController for instance, it can be created using plain code or it can be created from a XIB file.
In the end, it is not possible to add an extension that implements NSCoding.
Perhaps you can create a wrapper class that contains this class and have it implement NSCoding.

Related

Creating subclass of NSStackView

I try to create a subclass os NSStackView, for example to give it a special color.
To instantiate it, I have to call a superclasses designated init, if I understood right.
How can I detect, which are the designated initializers os NSStackView. Looking at https://developer.apple.com/documentation/appkit/nsstackview the only initializer I find is:
init(views: [NSView])
but the following code doesn't compile with "Must call a designated initializer of the superclass 'NSStackView'"
class CStackView: NSStackView
{ init(views: [NSView], withColor color: NSColor)
{ super.init(views: views)
// do something wich the color
}
required init?(coder decoder: NSCoder)
{ fatalError("init(coder:) has not been implemented")
}
}
init(coder:) seems to be a designated initializer, but I have want to init the CStackView with it´s subviews, not having a coder.
init(views:) is a convenience initializer.
NSStackView doesn't declare any designated initializers, so it inherits them from its superclass, NSView, which has init(frame:) and init(coder:)
You can either have your initializer call super.init(frame:) or declare your initializer as a convenience initializer and then it could call self.init(views:).
With #Dan s help, that´s it.
class C3StackView: NSStackView
{ convenience init(views: [NSView], withColor color: NSColor)
{ self.init(views: views)
// do something wich the color
}
required convenience init?(coder decoder: NSCoder)
{ fatalError("init(coder:) has not been implemented")
}
}

How to override SKScene init(fileNamed: fileNamed)

I have a SKScene class in which I need to implement a custom initializer that override the initializer init(fileNamed: fileNamed) of the SKScene superclass SKNode, in order to do some proprietary initializations but keep the possibility offered by init(fileNamed: fileNamed) to load the scene from the interface builder.
I have some trouble to find the right syntax. I've tried the following:
class Try: SKScene
{
override init(fileNamed: String)
{
super.init(fileNamed: fileNamed)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
But it returns the error : Initializer does not override a designated initializer from its superclass
It is however a designated initializer from a superclass, not the immediate superclass which is SKEffectNode, but the one above which is SKNode. How can I override the initializer in this case ?
J.
From the SWIFT docs:
Conversely, if you write a subclass initializer that matches a superclass convenience initializer, that superclass convenience initializer can never be called directly by your subclass, as per the rules described above in Initializer Delegation for Class Types. Therefore, your subclass is not (strictly speaking) providing an override of the superclass initializer. As a result, you do not write the override modifier when providing a matching implementation of a superclass convenience initializer.
If I understand this right this code should work:
convenience init?(fileNamed filename: String)
{
self.init(fileNamed: filename)
}

Make a class of type SKNode in swift

Im trying to make a class in swift that will be of type sknode that will also contain a parameter holding a position. I keep getting an error trying to create the class saying "initializer does not override a designated initializer from its super class" I'm not sure what I'm doing wrong, or how the class is supposed to be created.
import Foundation
import SpriteKit
class hud:SKNode {
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override init(position:CGPoint){
}
}
You are getting the "initializer does not override a designated initializer from its super class" error since you have marked your init(position: CGPoint) initializer as override.
SKNode has no such initializer so there is nothing to override.
Simply removing the override will rid you of the error, and your Hud class will have an initializer taking a CGPoint as a parameter.
init(position: CGPoint) {...}
It's worth noting that SKNode already has a property called position of type CGPoint, so it's possible that SKNode already have the capabilities you are after. Otherwise you'll likely want to call your property something else (such as myPosition) to avoid clashing with the existing property.
Remove the override keyword and don't forget to call the original initializer in your init method:
class hud:SKNode {
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
init(position:CGPoint){
super.init()
}
}

Extending SCNNode in Swift

I would like to extend SCNNode (if possible) in Swift. Here's my attempt:
class MyNode : SCNNode {
override init(geometry: SCNGeometry) -> SCNNode {
return super.init(geometry)
}
/* Xcode required this */
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
The -> operator is being tagged with an error "Consecutive declarations on a line must be separated by ;".
I know this is not right but if I humour Xcode it "fixes" it as follows:
override init(geometry: SCNGeometry); -> SCNNode {
Which is nonsense and then Xcode complains "Expected declaration".
I don't quite understand the SCNNode implementation - if I look at it in Xcode it's all declared as abstract (in comments) and offers no implementation. The docs do not suggest anything extends from SCNNode, you instantiate it directly, so I am assuming I should be able to extend it.
You can simply do:
class MyNode : SCNNode {
/* Xcode required this */
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Which will inherit the designated initialiser from the base class.
If you want to specify your own initialiser that takes a geometry, you must call a designated initialiser of the base class, so I'd say this would be what you'd want:
class MyNode : SCNNode {
init(geometry: SCNGeometry) {
super.init()
self.geometry = geometry
}
/* Xcode required this */
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
The initialiser you're seeing in the SCNNode.h code is an initialiser translated (automatically, I believe) from the Objective C method nodeWithGeometry. I believe this is a convenience initialiser, even though it's not specifically marked as such, which I'd personally say is a bug/limitation of the automatic header file translation. The documentation specifically says:
For consistency and simplicity, Objective-C factory methods get mapped as convenience initializers in Swift.
Don't be confused by the word abstract in the comments; this is the HeaderDoc tag for a short description of a method, i.e. "abstract" is used in the sense of an abridgement or summary.

Subclassing SCNScene in Swift - override init

I'm getting some compiler errors in Xcode 6 using Swift which I have a hard time wrapping my head around. I'm trying to create a scene by subclassing SCNScene, but keep getting errors on the initialisers. The basic structure of my code is:
class SpaceScene: SCNScene {
override init(named: String) {
super.init(named: named)
}
}
This results in an error on line 2 with the message "Initializer does not override a designated initializer from its superclass", although SCNScene clearly has such an initialiser. I think i'm missing something basic - any insights?
On XCode 6.1, the following should do it:
class SpaceScene : SCNScene {
override init() {
super.init()
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}