Confusion Regarding Overriding Class Properties in Swift
You are so close to being there, except that you can't override a static
property in a subclass — that is what it means to be static
. So you'd have to use a class
property, and that means it will have to be a computed property — Swift lacks stored class
properties.
So:
class ClassA {
class var thing : String {return "A"}
func doYourThing() {
print(type(of:self).thing)
}
}
class ClassB : ClassA {
override class var thing : String {return "B"}
}
And let's test it:
ClassA().doYourThing() // A
ClassB().doYourThing() // B
Swift: Override Subclass Properties that are also Subclasses of the Parent Class Property Class
Taken from here:
Overriding Property Getters and Setters
You can provide a custom getter (and setter, if appropriate) to
override any inherited property, regardless of whether the inherited
property is implemented as a stored or computed property at source.
The stored or computed nature of an inherited property is not known by
a subclass—it only knows that the inherited property has a certain
name and type. You must always state both the name and the type of the
property you are overriding, to enable the compiler to check that your
override matches a superclass property with the same name and type.
Seems like you cant do that.
Overriding a stored property in Swift
Why am I not allowed to just give it another value?
You are definitely allowed to give an inherited property a different value. You can do it if you initialize the property in a constructor that takes that initial value, and pass a different value from the derived class:
class Jedi {
// I made lightSaberColor read-only; you can make it writable if you prefer.
let lightSaberColor : String
init(_ lsc : String = "Blue") {
lightSaberColor = lsc;
}
}
class Sith : Jedi {
init() {
super.init("Red")
}
}
let j1 = Jedi()
let j2 = Sith()
print(j1.lightSaberColor)
print(j2.lightSaberColor)
Overriding a property is not the same as giving it a new value - it is more like giving a class a different property. In fact, that is what happens when you override a computed property: the code that computes the property in the base class is replaced by code that computes the override for that property in the derived class.
[Is it] possible to override the actual stored property, i.e.
lightSaberColor
that has some other behavior?
Apart from observers, stored properties do not have behavior, so there is really nothing there to override. Giving the property a different value is possible through the mechanism described above. This does exactly what the example in the question is trying to achieve, with a different syntax.
Can you override between extensions in Swift or not? (Compiler seems confused!)
It seems that overriding methods and properties in an extension works with the
current Swift (Swift 1.1/Xcode 6.1) only for Objective-C compatible
methods and properties.
If a class is derived from NSObject
then all its members are automatically available
in Objective-C (if possible, see below). So with
class A : NSObject { }
your example code compiles and works as expected. Your Code Data extension overrides
work because NSManagedObject
is a subclass of NSObject
.
Alternatively, you can use the @objc attribute for a method or property:
class A { }
class B : A { }
extension A
{
@objc var y : String { get { return "YinA" } }
}
extension B
{
@objc override var y : String { get { return "YinB" } }
}
Methods which are not representable in Objective-C cannot be marked with @objc
and cannot be overridden in a subclass extension. That applies for example to
methods having inout
parameters or parameters of an enum
type.
Swift: override property class
You can do something like this:
class PropertyBase { }
class PropA : PropertyBase {}
class PropB : PropertyBase {}
protocol ControllerBaseType {
associatedtype T: PropertyBase
var prop : T? { get set }
}
class ControllerA : ControllerBaseType {
var prop: PropA?
}
class ControllerB : ControllerBaseType {
var prop: PropB?
}
ControllerBaseType
is abstract as you want and you have the specific implementation of prop
in each subclass
EDIT:
According to @Honey comment, I simplified the code by removing type aliases from subclasses
EDIT2:
If you really need ControllerBase
as a class you can do this that way:
class ControllerBase<T: PropertyBase> {
var prop : T?
}
class PropertyBase { }
class PropA : PropertyBase {}
class PropB : PropertyBase {}
class ControllerA : ControllerBase<PropA> {}
class ControllerB : ControllerBase<PropB> {}
Weird ambiguity for class func() in inherited classes [Swift]
The reason is that the all
on Parent
and the all
on Mom
have different signatures. Thus, the all
on Mom
cannot be an override for that on Parent
(also shown by the fact that the compiler does not require the override
keyword). What this means is that two class functions named all
exist on the Mom
type. Furthermore, the closure you are passing to forEach
does not specify a parameter type, so it is impossible to be sure of which of the two functions is being referenced. Assigning a type to the mom
parameter in the forEach
will solve this problem.
Inheriting ugly: Swift subclass alters superclass' view of own stored properties?
The following example code demonstrates that a Swift superclass experiences its own properties through outermost subclass overrides!
(The example below proves @RobNapier correct, which I initially confirmed by successfully overriding UIResponder.inputAccessoryViewController
and observing my viewController activated when the keyboard pops up for my subclassed UITextView : UIResponder
)
The Good:
Swift overrides as explained by @RobNaipier in comments, make sense, at least from certain points of view. And can obviously be exploited for its interesting flexibility
The Bad:
However, it isn't what I assumed, and I was somewhat stunned that inheritance works that way, because intuitively I realized that letting subclasses tamper with superclasses` view of themselves is potentially risky, especially if one doesn't know superclass implementation details (as is the case with UIKits proprietary implementation code Apple doesn't release the source to the public).
The Ugly:
So while Swift inheritance lets the inheritors achieve tweak things for interesting or useful effect, and could be very handy in some cases, in practical use, for example with UIKit, it does leads to anticipated problems and confusion.
The coup de grâce, which I'm grateful that Rob pointed out, is that, due to the anticipated downsides, class inheritance with UIKit is increasingly discouraged by Apple and struct+protocol has been adopted by SwiftUI.
class TheSuperclass {
var x = 5
init() {
print("How superclass sees it before subclass initialized: x = \(x)")
}
func howSuperclassSeesItselfAfterSubclassInit() {
print("How superclass sees it after subclass initialized: x = \(x)")
}
}
class TheSubclass : TheSuperclass {
override var x : Int {
get { super.x + 10 }
set { super.x = newValue }
}
override init() {
super.init()
print("How subclass sees it after superclass" +
"initialized: x = \(x), super.x = \(super.x)")
}
}
TheSubclass().howSuperclassSeesItselfAfterSubclassInit()
The above code when run in Playground displays the following:
How superclass sees it before subclass initialized: x = 5
How subclass sees it after superclass initialized: x = 15, super.x = 5
How superclass sees it after subclass initialized: x = 15
Why do we override initializers in Swift?
Subclasses might not inherit their superclass initializers "by default", but they can be inherited (e.g. if you don't supply any designated initializers, you will automatically inherit all of the designated initializers of the superclass ... see Automatic Initializer Inheritance).
Consider a Dog
subclass called Chihuahua
: If you don't implement any designated initializers in Chihuahua
, you automatically inherit the Dog
initializers with no extra code on your part. But if you do need to override it for some reason, do so and you just need to call a Dog
designated initializer from your Chihuahua
designated initializer. And if your Chihuahua
initializer has the same signature as a Dog
designated initializer, then you must explicitly supply the override
keyword.
Class inheritance, overriding methods and accessing stored properties from superclass
You're very, very close. Your only mistake is that x
and y
are not properties of Machine
. They're properties of Machine.location
.
Your self.location = Point(x: x+1, y)
should work, so I'm curious what "without success" means there. The simpler way is exactly as you've done, but modifying the location:
case "Up":
location.y++
Likely unrelated, but your Point
would be significantly better implemented as a struct
rather than a class
. Using a Point
as a mutable reference type (a class that includes var
properties) can lead to a lot of confusion. If two Robot
instances are passed the same Point
, then modifications to one will also modify the other, which would be very surprising. A struct
, on the other hand, is a value type. If you pass it to something, the receiver gets its own copy.
Reference types (classes) are best used when the thing has an identity and its own state. Two robots at the same location are still different robots. But two points at the same location are the same point. That means points are values and should be a struct
.
Related Topics
How to Override Layerclass in Swift
Changing Tab Bar Font in Swift
Difference Between Switch Cases "@Unknown Default" and "Default" in Swift 5
Combining Two Conditions in Nspredicate
Swift Check Type Against a Generic Type
Get Rawvalue from Enum in a Generic Function
Performseguewithidentifier in Swift
How to Zip More Than 4 Publishers
Uisearchcontroller in Navigationitem iOS 11 Apple Way
Swiftui: Detect Finger Position on MAC Trackpad
Forcing Nspersistentcontainer Change Core Data
Realitykit - Set Text Programmatically of an Entity of Reality Composer
One-Way Platform Collisions in Sprite Kit
How to Highlight a Uitextview's Text Line by Line in Swift