How to override private var in superclass - swift

So I have the following superclass:
class Vehicle {
private var _maxSpeed: Int = 100
var maxSpeed: Int {
get {
return _maxSpeed
}
var tooFast: Bool {
get {
if maxSpeed >= 140 {
return false
} else {
return true
}
}
}
}
Plus I have some subclasses in which I want to override maxSpeed... per example:
class SuperCar: Vehicle {
//override the maxspeed...
}
But how should I approach this? Or is this only possible if we don't make it private? I tried to throw the private part out of the window but that won't work as well...
class Vehicle {
var maxSpeed: Int = 100
var tooFast: Bool {
get {
if maxSpeed >= 140 {
return false
} else {
return true
}
}
}
}
class SuperCar: Vehicle {
// override the maxSpeed...
override var maxSpeed: Int = 200
// Will not work...
}

Just put the class and subclass in the same file. private has nothing to do with inheritance. It has to do with file scope. Anything in the same file has access to private members.
That said, you almost certainly shouldn't be using inheritance here. Vehicle should almost certainly be a protocol. Then you wouldn't have any of the headaches of inheritance or private.
protocol Vehicle {
var maxSpeed: Int {get}
}
extension Vehicle {
// Default implementation if none is given
var maxSpeed: Int { return 100 }
// Another method that applies to all Vehicles
var tooFast: Bool {
return maxSpeed < 140 // (feels like this should be >= 140, but matching your code)
}
}
struct SuperCar: Vehicle {
// override the default implementation for the protcocol
var maxSpeed = 200
}

Set your private member variables in the init method
class Vehicle{
private var maxSpeed: Int
init(maxSpeed: Int = 100){
self.maxSpeed = maxSpeed
}
}
class SuperCar: Vehicle {
override init(maxSpeed: Int = 200){
super.init(maxSpeed: maxSpeed)
}
}

For a Swift 3 version of Rob's answer, you can't override private, but interestingly you can with fileprivate computed properties. You have to put the class in the same file though.
I did this today:
protocol Renderer {
}
class BaseClass {
private let _renderer: Renderer = BaseClassRenderer()
fileprivate var renderer: Renderer {
return _renderer
}
}
class Subclass: BaseClass {
private let _renderer: Renderer = SubclassRenderer()
override fileprivate var renderer: Renderer {
return _renderer
}
}

you can override computed property
class C {
var a: Int { return 10 }
}
class D:C {
override var a: Int { return 100 }

Related

Generic protocol for observing changes in Swift 5

Trying hard to code in Swift 5 the Java example below.
Generally, I want to have an Observable protocol which will be adopted by multiple other protocols. I need these protocols to be types in functions' arguments, so that these functions can add additional observers.
In Java, it is very easy to do. The code prints out:
Observer 1 changed to 10
Observer 2 changed to 10
,
interface Observable<O> {
void addObserver(O observer);
}
interface Settings extends Observable<SettingsObserver> {
void setInterval(int interval);
}
interface SettingsObserver {
void intervalChanged(int interval);
}
class AppSettings implements Settings {
private List<SettingsObserver> observers = new ArrayList<>();
#Override public void addObserver(SettingsObserver observer) { observers.add(observer); }
#Override public void setInterval(int interval) { observers.forEach(observer -> observer.intervalChanged(interval)); }
}
class Observer1 implements SettingsObserver {
#Override public void intervalChanged(int interval) {
System.out.println("Observer 1 changed to " + interval);
}
}
class Observer2 implements SettingsObserver {
#Override public void intervalChanged(int interval) {
System.out.println("Observer 2 changed to " + interval);
}
}
class Main {
public static void main(String[] args) {
Observer1 observer1 = new Observer1();
Settings settings = new AppSettings();
settings.addObserver(observer1);
Main main = new Main();
main.run(settings);
}
void run(Settings settings) {
Observer2 observer2 = new Observer2();
settings.addObserver(observer2);
settings.setInterval(10);
}
}
While it's simple to create a generic wrapper to which you can add your own observables, there are two native solutions that you should use instead.
Notifications.
When value is changed, send a notification using NotificationCenter.default. Observers should listen to these notifications. Notification are a crucial part of the ecosystem:
class AppSettings {
enum Notifications {
static let intervalChanged = Notification.Name("AppSettingsIntervalChangedNotification")
}
var interval: TimeInterval = 0 {
didSet {
NotificationCenter.default.post(name: Notifications.intervalChanged, object: self)
}
}
}
let settings = AppSettings()
let observer = NotificationCenter.default.addObserver(
forName: AppSettings.Notifications.intervalChanged,
object: settings,
queue: nil
) { [weak settings] _ in
guard let settings = settings else { return }
print(settings.interval)
}
settings.interval = 10
Key-value observing (KVO)
If you inherit your objects from NSObject, you can simply add a direct observer to any Obj-C compatible value:
class AppSettings: NSObject {
#objc dynamic var interval: TimeInterval = 0
}
let settings = AppSettings()
let observer: NSKeyValueObservation = settings.observe(\.interval, options: .new) { _, change in
print(change.newValue)
}
settings.interval = 10
See https://developer.apple.com/documentation/swift/cocoa_design_patterns/using_key-value_observing_in_swift
Just for completeness a simple generic observer here:
class Observable<ValueType> {
typealias Observer = (ValueType) -> Void
var observers: [Observer] = []
var value: ValueType {
didSet {
for observer in observers {
observer(value)
}
}
}
init(_ defaultValue: ValueType) {
value = defaultValue
}
func addObserver(_ observer: #escaping Observer) {
observers.append(observer)
}
}
class AppSettings {
let interval: Observable<TimeInterval> = Observable(0)
}
let settings = AppSettings()
settings.interval.addObserver { interval in
print(interval)
}
settings.interval.value = 10
Note that all my observers are simple closures. The reason why Java uses objects as observers is mostly historical due to Java limitations. There is no need for Observable or Observer protocols in Swift.
Depending on your needs, you may be able to get by with property observers in Swift. It allows you to take action when a property is going to be changed or has changed. It is also less complicated than a full observerable type.
Here is Apple's example from the Swift manual:
class StepCounter {
var totalSteps: Int = 0 {
willSet(newTotalSteps) {
print("About to set totalSteps to \(newTotalSteps)")
}
didSet {
if totalSteps > oldValue {
print("Added \(totalSteps - oldValue) steps")
}
}
}
}
let stepCounter = StepCounter()
stepCounter.totalSteps = 200
// About to set totalSteps to 200
// Added 200 steps
stepCounter.totalSteps = 360
// About to set totalSteps to 360
// Added 160 steps
stepCounter.totalSteps = 896
// About to set totalSteps to 896
// Added 536 steps
You would want to use the didSet() function. You could also call another function within the observer.
You could also use the property observers to write a simple observable-like class if you do not want to use a framework such as RxSwift or Apple's new Combine.
Here is a simple example that just uses closures instead of classes:
class ClassToWatch {
typealias ObservingFunc = (ClassToWatch) -> Void
private var observers: [ObservingFunc] = []
func addObserver(_ closure: #escaping ObservingFunc) {
observers.append(closure)
}
private func valueChanged() {
observers.forEach { observer in
observer(self)
}
}
var value1: Int = 0 {
didSet {
valueChanged()
}
}
var value2: String = "" {
didSet {
valueChanged()
}
}
}
var myclass = ClassToWatch()
myclass.addObserver { object in
print("Observer 1: \(object.value1) \(object.value2)")
}
myclass.addObserver { object in
print("Observer 2: \(object.value1) \(object.value2)")
}
myclass.value1 = 3
myclass.value2 = "Test"
Your Java code could be directly translated into Swift code. Here is my translation, with some degree of "Swiftification":
protocol Observable {
associatedtype ObserverType
func addObserver(_ observer: ObserverType)
}
protocol Settings : Observable where ObserverType == SettingsObserver {
var interval: Int { get set }
}
protocol SettingsObserver {
func intervalDidChange(newValue: Int)
}
class Observer1 : SettingsObserver {
func intervalDidChange(newValue: Int) {
print("Observer 1 changed to \(newValue)")
}
}
class Observer2 : SettingsObserver {
func intervalDidChange(newValue: Int) {
print("Observer 2 changed to \(newValue)")
}
}
class AppSettings: Settings {
var interval: Int = 0 {
didSet {
observers.forEach { $0.intervalDidChange(newValue: interval) }
}
}
private var observers: [SettingsObserver] = []
func addObserver(_ observer: SettingsObserver) {
observers.append(observer)
}
}
let settings = AppSettings()
settings.addObserver(Observer1())
settings.addObserver(Observer2())
settings.interval = 10
Although Observable cannot be used as a parameter type, the protocols that derive from it that also specifies the associated type, can.
You could go one step further and make SettingsObserver a typealias of (Int) -> Void. This way you don't need all those different ObserverX classes.
typelias SettingsObserver = (Int) -> Void
The addObserver calls would then become:
settings.addObserver { print("Observer 1 changed to \($0)") }
settings.addObserver { print("Observer 2 changed to \($0)") }
And the call in didSet would change to:
observers.forEach { $0(interval) }
Also, I don't understand why Settings exist. Can't you just conform AppSettings directly to Observable? I mean, I know the idea of program to interface and all that, but IMO this is a bit too much...

EXC_BAD_ACCESS during iterating through array of protocol witnesses

I'm a cocos2d developer and currently we are working on a Swift port. I've encountered into a very strange problem which I suspect is a Swift compiler bug, but maybe it is still me.
I have the following code
public protocol Tagged {
var tag: Int { get set }
}
public protocol Component: Tagged {
weak var owner: Node? { get /*set*/}
func onAdd(to owner: Node)
func onRemove()
}
open class ComponentBase: Component {
public weak var owner: Node?
open var tag: Int = 0
open func onAdd(to owner: Node) {
self.owner = owner
}
open func onRemove() {
self.owner = nil
}
}
public protocol FixedUpdatable: class, Prioritized {
func fixedUpdate(delta: Time)
}
open class CustomComponent: ComponentBase, FixedUpdatable {
}
open class Node: Responder {
// MARK: Components
/// Array of components added to the node
internal(set) public var components = [Component]()
internal var fixedUpdatableComponents = [FixedUpdatable & Tagged]()
public func add(component: Component) -> Bool {
...
components.append(component)
component.onAdd(to: self)
...
if let c = component as? FixedUpdatable & Tagged {
// TODO: Insert with priority in mind
fixedUpdatableComponents.append(c)
// If it is first component
if isInActiveScene && fixedUpdatableComponents.count == 1 {
scene.scheduler.schedule(fixedUpdatable: self)
}
}
}
}
extension Node: FixedUpdatable {
public final func fixedUpdate(delta: Time) {
fixedUpdatableComponents.forEach { $0.fixedUpdate(delta: delta) }
}
}
// Then in Scheduler I have
for t in self.fixedUpdatableTargets {
t.fixedUpdate(delta: timer.repeatInterval)
}
And it crashes during iteration, more exactly during execution of the first closure.
Should I file a bug to an Apple team? I tried a lot of things and none of them worked (recasting objects again in the closure, overriding tag property in many ways).
UPDATE:
This works:
for c in fixedUpdatableComponents as [FixedUpdatable] {
c.fixedUpdate(delta: delta)
}
This doesn't:
fixedUpdatableComponents.forEach { $0.fixedUpdate(delta: delta) }
fixedUpdatableComponents.forEach { let c = $0 as FixedUpdatable; c.fixedUpdate(delta: delta) }
for c in fixedUpdatableComponents { c.fixedUpdate(delta: delta) }
for c: FixedUpdatable in fixedUpdatableComponents { c.fixedUpdate(delta: delta) }
Remember that fixedUpdatableComponents is [FixedUpdatable & Tagged]

How to initialize variables inside subclasses' initializer that will be used in the super class's initializer?

In the following code, my intention is to have repeatNum declared in the base class because it is used in the base class (inside init and other functions). And each subclass should set repeatNum because only the subclass knows its own value.
class Base {
var repeatNum: Int
init() {
for var i=0; i<repeatNum; ++i {
print("*")
}
}
}
class SubClass1 : Base {
override init() {
repeatNum = 10
super.init()
}
}
class SubClass2 : Base {
override init() {
repeatNum = 5
super.init()
}
}
Of course, it prompts some errors:
For the base class:
'self.repeatNum' not initialized
Return from initializer without initiating all stored properties.
For the subclasses:
use of 'self' in property access 'repeatNum' before super.init initializes self
I know I can simply call super.init() before setting repeatNum in the subclasses, but I really need to use repeatNum inside the base's init() in the real case. It becomes a paradox for me here somehow.
I also understand I can change the design to make the errors go away, but I am wondering if it's possible to achieve my original intention with some tweaks? I probably miss something here.
Your current code doesn't even compile, does it? It should complain about trying to use repeatNum before being initialized...
Maybe something like this could be an option for you?
class Base {
var repeatNum: Int
init(repeatNum: Int) {
self.repeatNum = repeatNum
for _ in 0..<repeatNum {
print("*")
}
}
}
class SubClass1 : Base {
init() {
super.init(repeatNum: 10)
}
}
class SubClass2 : Base {
init() {
super.init(repeatNum: 5)
}
}
i don't know what is you want,the following code is that ok
class Base {
var repeatNum: Int?
init() {
}
func printyourneed(){
for var i=0; i<repeatNum; ++i {
print("*")
}
}
}
class SubClass1 : Base {
override init() {
super.init()
self.repeatNum = 10
self.printyourneed()
}
}
class SubClass2 : Base {
override init() {
super.init()
self.repeatNum = 5
self.printyourneed()
}
}
or
class Base {
var _repeatNum:Int?;
var repeatNum: Int?{
get{
return _repeatNum
}
set{
_repeatNum = newValue
printyourneed()
}
}
init() {
}
func printyourneed(){
for var i=0; i<repeatNum; ++i {
print("*")
}
}
}
class SubClass1 : Base {
override init() {
super.init()
self.repeatNum = 10
}
}
class SubClass2 : Base {
override init() {
super.init()
self.repeatNum = 5
}
}

Inheriting a class that conforms to a protocol

I can not figure out why Xcode playground is crashing, here is my basic setup
protocol Shootable {
func shoot()
}
class BaseMissile: Shootable {
var damage = 0
func shoot() {
println("Pew pew for \(damage) damage")
}
}
class Missile1: BaseMissile {
override init() {
super.init()
damage = 1
}
}
protocol Targetable {
var life: Int {get set}
}
class BaseSpaceship: Targetable {
var life = 0
var currentMissile: BaseMissile!
func printHealth() {
println("My current life: \(life)")
}
}
class Spaceship1: BaseSpaceship {
override init() {
super.init()
life = 1
currentMissile = Missile1()
}
}
var spaceship = Spaceship1()
spaceship.printHealth()
spaceship.currentMissile.shoot()
specifically the last line spaceship.currentMissile.shot() crashes the playground. If I move var currentMissile: BaseMissile! from BaseSpaceship to Spaceship1 it works, but is that an acceptable way to handle this?
I guess this happens because BaseSpaceship class has no initializers and var currentMissile: BaseMissile! cant be nil. So you either should do it optional by replacing ! with ? or give it a default value.

Swift: class and properties - all only initialized once

I'm looking to have a class or struct (does not matter) with properties, where everything may only be initialized once in the app. Any attempt to modify the class or its properties will fail or not be possible.
Is this possible?
I've come up with this so far:
public struct ScreenInfo
{
static var scaleFactor:Int = 0
public init(initialScaleFactor:Int)
{
if (ScreenInfo.scaleFactor == 0) {
ScreenInfo.scaleFactor = initialScaleFactor
}
}
public static func getScaleFactor()
-> Int
{
return scaleFactor
}
}
let si1:ScreenInfo = ScreenInfo(initialScaleFactor:11)
ScreenInfo.getScaleFactor() // = 11
let si2:ScreenInfo = ScreenInfo(initialScaleFactor:22)
ScreenInfo.getScaleFactor() // = 11
What you want is somewhat unusual, but it is possible.
public struct ScreenInfo {
private static var _scaleFactor: Int?
public static var scaleFactor: Int? {
set {
if _scaleFactor == nil {
_scaleFactor = newValue
} else {
// Optionally throw an exception or something
}
}
get {
return _scaleFactor
}
}
}
ScreenInfo.scaleFactor // nil
ScreenInfo.scaleFactor = 5
ScreenInfo.scaleFactor // 5
ScreenInfo.scaleFactor = 15
ScreenInfo.scaleFactor // 5