I'm trying to create a subclass in which I will add more functions and properties to the SCNParticleSystem object.
The SCNParticleSystem header file in Swift has only this init declared:
public convenience init?(named name: String, inDirectory directory: String?)
So, what I want to do is use the same parameters as the init but also add a custom parameter to the init like this and do some setup for my properties:
init how ? (particleSystemFileName:String, inDirectory:String, parentNode:SCNNode)
{
init who ?
<setup my stuff>
}
I just can't figure out how to do this?
thx
It's just not possible to create convenience init from subclass to call convenience init in superclass. Why? Initializers has to follow 3 rules:
A designated initializer must call a designated initializer from its
immediate superclass.
A convenience initializer must call another initializer from the
same class.
A convenience initializer must ultimately call a designated
initializer.
Diagram that shows what you can actually do with initializers & subclassing (more on that topic):
What you can do is some sort of setup() method that will customize your created instance of a subclass with given properties.
Related
I am trying to understand the syntax for initializers and how they work. I am reading the swift documentation and I am having a hard time understanding how they work in a specific example I am working on. I'm following a tutorial to learn about core data but I do not want to continue through the project until I understand how the initialization code works (or any other concept I do not understand).
https://docs.swift.org/swift-book/LanguageGuide/Initialization.html
Core Data: Note Entity Class
Core Data: Note Class Convenience Initializer
In the first image above I show the Note Entity Class that Core Data creates and in the second image I add a convenience init(). All the extra on the code in the extension of the Note class is my notes.
The first two comments on the extension of the Note class is what I have found out about how the entity class hierarchy which is that the super class is the NSMangedObject (super class) then the sub class is the Note entity class. To my understanding the NSMangedObject class has 3 initializers which are:
init() - Default Initializer
init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) - Designated Initializer
convenience init(context moc: NSManagedObjectContext) - Convenience Initializer
Then Note entity class the only thing I have is the convenience init(title: String, context: NSManagedObjectContext). For this initializer I understand how the title and creationDate are initialized but my question is on the self.init(context: context).
Question: To my understand reading the Swift documentation a convenience initializer cannot point to another convenience initializer which is what I think it's happening here?? I think that the default initializer from the Note class is pointing to the initializers from the super class of NSMangedObject. Can anyone provide me with some insight to understand what is happening.
A convenience initializer must call another initializer in self. That is all it is required to do. It must do that before saying self for any other purpose.
In the Node extension, the convenience initializer is doing that; it is starting out by calling self.init(context:).
That is legal because Node is an NSManagedObject subclass (representing an entity), so it inherits that initializer:
https://developer.apple.com/documentation/coredata/nsmanagedobject/1640602-init
That's all there is to know. The fact that init(context:) is a convenience initializer is not interesting. It's an initializer of self, that's all that matters.
I am trying to design a subclass of a SKShapeNode that takes on a specific width and height and only takes a position in it's initializer. Basically I want a class that makes identical boxes but allows me to initialize them with different starting positions.
When I tried to implement this I am getting an error that tells me Must Call a designated initializer of the superclass 'SKShapeNode'
I do not understnad how what I implemented does not called a designated initializer. Am I not allowed to set a general predetermined initializer for the subclass to call in the super?
When I attempt to make this a convenience initializer, like the message suggests, the self tag has no initializer properties to use. Honestly, what I have coded is exactly what I want to happen, I just need someone to help me make it do this thing.
SKShapeNode doesn't define a designated initializer, so it inherits SKNode's, which is init(). Your class does define a designated initializer: init and (unintentionally) init(coder:). By making a non-convenience initializer, you disabled initializer inheritance and made it impossible to use the convenience initializers of your superclass.
Instead, you want to just chain a new convenience init to SKShapeNode's convenience init. To do that, get rid of the "coder" init, and mark your init convenience. Then it can chain to other inherited convenience inits by calling self.init(...):
class DigitObject: SKShapeNode {
convenience init(x: CGFloat, y: CGFloat) {
self.init(rect: CGRect(x: x, y: y, width: CGFloat(9*3), height: CGFloat(9*5)))
}
}
For more on the rules, see Initializer Delegation for Class Types
. For more on why it works this way, see Why can’t we call superclass convenience initializer from subclass? And for a little fun about why Swift cares so much about this, you can watch James Dempsey sing about how less-strict rules burned us in Objective-C.
Is there difference ? And the effect of deinit ?
struct mark {
var mark: Int
}
struct mark {
var mark: Int
init(mark: Int) {
self.mark = mark
}
}
init is used to set initial values for properties on a struct or class type at the time it is created, before any other methods may be called on it and before it is passed as a parameter to other functions or methods.
In Swift, any non-optional properties must be set with initial values before init returns. Properties may be declared with initial values already, which excludes them from having to be set in an init method.
class types must have an init method implemented if there are any non-optional properties not already declared with initial values.
For struct types only, Swift will automatically generate an init method with parameters for each non-optional property that was not already declared with an initial value. You can optionally create any number of alternative init methods for the struct, as long as by the time each one returns, all non-optional properties have a value.
In your example, there is no difference between the init method created on the second line, and the automatically created init method provided for that struct type by Swift. But you could create alternate initializers that, for example, take a Double instead of an Int and then convert it internally before setting the mark property.
I think the key point to realize is that even when you do not specify an init method yourself, one still exists, as created automatically by Swift for struct types. So in both line one and line two of your example, an init method is being called (and they are essentially identical implementations). The only difference is that you wrote the init implementation in the second line, and the Swift compiler writes the init method in the first line.
deinitonly exists for class types, which are passed by reference and have memory management. Any deinit method you declare on a class you create will be called when there are no more references to that instance of the class and it will be released from memory. It's used to deregister from various observation patterns or otherwise clean up right before the instance is destroyed.
I thought both these classes conformed to the rules of inherited initializers:
class Butt1 : UIButton {}
class Butt2<T> : UIButton {}
let butt1 = Butt1() // ok
let butt2 = Butt2<Void>() // error: no accessible initializer
The docs say:
As mentioned above, subclasses do not inherit their superclass
initializers by default. However, superclass initializers are
automatically inherited if certain conditions are met. In practice,
this means that you do not need to write initializer overrides in many
common scenarios, and can inherit your superclass initializers with
minimal effort whenever it is safe to do so.
Assuming that you provide default values for any new properties you
introduce in a subclass, the following two rules apply:
Rule 1 If your subclass doesn’t define any designated initializers, it
automatically inherits all of its superclass designated initializers.
Rule 2 If your subclass provides an implementation of all of its
superclass designated initializers—either by inheriting them as per
rule 1, or by providing a custom implementation as part of its
definition—then it automatically inherits all of the superclass
convenience initializers.
In the case of Butt2 the compiler doesn't think it's "safe to do so", but why isn't it safe?
In Swift, I am trying to create subclasses of a class which will add properties and methods that are specific to certain instances of the class. I would like to initialize an instance of a subclass with an instance of the class, such that the class properties of the subclass instance actually refer to the class instance from which it initialized. My goal is to be able to set a class property in the subclass instance, and have it also set the same property in the class instance from which it was initialized. I have not been able to find a way to create an initializer which accomplishes this, even if I set all the class properties to be the same for the subclass instance and the class instance. The only way I have been able to do this is to add a variable to the subclass and set it to the class instance, but this is cumbersome. Is there a way to do this?
You need to add an appropriate init like this:
class A {
// ...
}
class B:A {
init(clone:A) {
// assign from the other object what needed
}
}