Confusion Regarding Overriding Class Properties in Swift

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



Leave a reply



Submit