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?
Related
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.
I want to write a PAT and I don't care about Obj-C interoperability. The #nonobjc attribute sounds perfect but its designed for variables and methods only.
Anything similar for hiding protocols from Obj-C?
You seem to be misunderstood what the #nonobjc attribute is for:
From the docs:
nonobjc
Apply this attribute to a method, property, subscript, or initializer
declaration to suppress an implicit objc attribute.
If you scroll further down the page, it tells you what will have an implicit objc attribute on them:
The compiler implicitly adds the objc attribute to subclasses of any class defined in Objective-C. However, the subclass must not be generic, and must not inherit from any generic classes. [...] The objc attribute is also implicitly added in the following cases:
The declaration is an override in a subclass, and the superclass’s declaration has the objc attribute.
The declaration satisfies a requirement from a protocol that has the objc attribute.
The declaration has the IBAction, IBSegueAction, IBOutlet, IBDesignable, IBInspectable, NSManaged, or GKInspectable
attribute.
This does not include protocols, so protocols are never implicitly exposed to Objective-C. This means that you don't need the nonobjc attribute on protocols to suppress implicit objcs on protocols. Protocols, by default, are not exposed to Objective-C, unless you mark them with #objc.
For methods it is clear to me that accidentally overriding a method could have bad consequences, so requiring developers to be explicit about it with the "override" keyword seems like a good idea.
However, as initialisers are invoked on a type (as it were) instead of on an object, I don't understand what overriding means in this context nor what kind of mistakes the requirement for the "override" keyword on initialisers is preventing.
I find the override modifier to provide only a convenience and safety function of expressing the intent of a developer to either override an existing member of a class (when the modifier is present) or to introduce a new one (when the modifier is missing) so the compiler can perform the corresponding compile-time checks and inform the developer if the expressed intent could not be implemented (because there is nothing to override or because there is a signature collision with a member defined in one of the base classes).
You can argue that there is a difference between overriding a virtual member or providing a distinct statically dispatched initializer replicating the signature of an initializer of the base class. Technically, yes; but not semantically. Semantically you may still want to replicate the signature of an initializer of the base class, and the compiler is ready to perform the corresponding compile-time signature checks.
The Swift Language Guide in the chapter "Initialization" under the title Initializer Inheritance and Overriding says:
When you write a subclass initializer that matches a superclass designated initializer, you are effectively providing an override of that designated initializer. Therefore, you must write the override modifier before the subclass’s initializer definition. ...
As with an overridden property, method or subscript, the presence of the override modifier prompts Swift to check that the superclass has a matching designated initializer to be overridden, and validates that the parameters for your overriding initializer have been specified as intended.
From this excerpt the role of the override modifier indeed appears to be small — to verify the intent of a developer to match a signature from the base class or not.
The rule for access control for required initializer seems to be different than one that does not specify required. Why?
public class A {
// required init() must be public, why?
public required init() { }
}
public class B {
// init() does not need to be public, why?
init() { }
}
First, let's make the rule clear. It is not required for required initializers to be marked as public. It is only required that required initializers be as accessible as the class is. If your class is public, it's required initializers must also be public. If your class is internal, its required initializers must also be internal (technically, you could make it public, but that'd make no sense and generates a warning). And of course, if your class is private, the required initializer should also be private.
So, why?
There are two reasons here, but they require an understanding of what the required keyword is actually doing.
First of all, the required keyword is guaranteeing this class and all of its subclasses implement this particular initializer. One of the main reasons to make an initializer required is for protocol conformance, with the most popular example of this being NSCoding, which requires the init(coder:) initializer. So with that in mind, let's consider a class which is trying to implement this protocol:
public class MySwiftClass: NSObject, NSCoding {
// some implementations
// including the two requirements of the NSCoding protocol
}
Now, consider trying to use this:
let mySwiftObject = MySwiftClass(coder: aCoder)
We should be able to do this without problem, right? I mean, after all, MySwiftClass conforms to NSCoding protocol, and NSCoding protocol guarantees there will be an init(coder:) initializer.
But if you were allowed to mark init(coder:) as a lower access level than the class had, there would be a scope within which the class can be seen, but its required initializer could not be accessed... so despite knowing that this class conforms to a protocol with a required initializer or is inherited from a parent class with a required initializer, we'd somehow not be able to call that required initializer because for the scope we are in, it would appear to not exist.
The second reason is for subclassing itself.
Let's take this example parent class:
public class ParentClass {
required init() {}
}
We want the zero-argument initializer to be required. That means, if anything inherits from ParentClass, it must also be sure that the zero-argument initializer is implemented. But if we are allowed to let the required initializer to have a lesser scope than the class itself, then there is a scope within which we can see the class, but we cannot see the required initializer, so how can subclasses created in that scope manage to even know there is a required initializer that they must implement?
I've never worked with objective C but have a fair bit of experience with C++.
What exactly is the difference between a superclass and a protocol in objective C? I read that a protocol is essentially a pure virtual class, but is that it? Is a protocol simply a specific type of superclass?
A protocol is a contract a class is going to conform to. When a class conforms to a protocol it tells the compiler that it will implement all the methods and all the properties declared in the protocol.
In Objective-C the class additionally needs a superclass. In a lot of cases this is NSObject. The superclass implements already a lot of methods (like isEqual:). A protocol never implements any methods or defines any property.
A protocol tells which properties/operations a class must implement. A superclass implements them and you can add your own stuff on top.
A protocol defines a set of method definitions that a class or struct must implement, very much like a Java interface.
A superclass is the class from which a given class inherits its method definitions, the implementation for those methods, and the instance and class properties.