Swift Choosing Specific Value by Condition - swift

I am applying a simple inheritance project using Swift. However, after completing my code, getting this error all the time.This project creates vehicle class and has 2 child classes as Car and Bicycle.
Car has speed depending on its chosen gear.
So I implement a gearBox dictionary which has gear as key and speed as value.
I am not sure if I could assign speed value by controlling its gear in my Car class.
Any help would be appreciated.
MY ERROR
Playground execution failed: error: psionix.playground:19:34: error: use of 'self' in property access 'speed' before super.init initializes self
super.init(speedVehicle: speed)
^
MY CODE
//: Playground - noun: a place where people can play
import UIKit
class Vehicle{
var speed : Double
init(speedVehicle:Double){
speed = speedVehicle
}
func printDescription(){
print("Vehicle has \(speed) km/h speed by default.")
}
}
class Car : Vehicle{
var speedCar :Double
let gearBox : [Int : Double] = [1:10.5, 2:23.3, 3:33.4, 4:45.0, 5:51.2]
init(){
super.init(speedVehicle: speed)
}
func calculateTravelTime(distance:Double, gearCar:Int)->Double{
var travelTime : Double
travelTime = distance/speedCar
for (gear, speed) in gearBox{
if(gear == gearCar){
speedCar = speed
}
}
return travelTime
}
override func printDescription() {
print("My Car has \(gearBox.count) gears and has \(speedCar) km/h speed.")
}
}
class Bicycle : Vehicle{
var hasBasket : Bool
var distance : Double // in km
var speedBicycle : Double
init(hasBasket: Bool){
super.init(speedVehicle: speed)
self.hasBasket = hasBasket
}
func calculateTravelTime(speed:Double)->Double{
let time = (distance/speed)
print("Bicycle travel time is: \(time)")
return time
}
override func printDescription() {
if(hasBasket == true){
print("My Bicycle has \(speedBicycle) km/h speed and its has a basket.")
}
else{
print("My Bicycle has \(speedBicycle) km/h speed and its has no basket.")
}
}
}
let myVehicle = Vehicle(speedVehicle:3.0)
myVehicle.printDescription()
let myCar = Car()
print("My car travel time is \(myCar.calculateTravelTime(distance: 100.0, gearCar:3)) hours.")
myCar.printDescription()
let myBicycle = Bicycle(hasBasket:true)
print("My bicycle travel time is \(myBicycle.calculateTravelTime(speed: 10)) hours.")
myBicycle.printDescription()

The problem is you are trying to call the initializer of your superclass without actually providing all necessary values as input arguments to super.init(speed:). You need to change your init methods to provide a speed value.
class Car : Vehicle{
...
init(speed: Double){
super.init(speedVehicle: speed)
}
}
class Bicycle : Vehicle{
...
init(speed: Double,hasBasket: Bool){
super.init(speedVehicle: speed)
self.hasBasket = hasBasket
}
}
And do the same for all your Vehicle subclasses. Moreover, the speedCar property is not needed, since Car already has a speed property inherited from Vehicle, same for speedBicycle in Bicycle.
If you want all your subclass instances to have the same speed, just set up a default value in the init method like so:
class Car : Vehicle{
...
init(){
let carSpeed = 50.0
super.init(speedVehicle: carSpeed)
//you could even do super.init(speedVehicle: 50), I just used a variable for clarity
}
}
Moreover, you should never iterate through a dictionary to find a certain key, you can safely access values using subscripting. If the key doesn't exist, the value will simply be nil.
func calculateTravelTime(distance:Double, gearCar:Int)->Double{
if let currentSpeed = gearBox[gear] {
speedCar = currentSpeed
}
return distance/speedCar
}

You are init your Bicycle and Car, before you set it speed. Add speed before you called super.init method
Edit this
init(hasBasket: Bool){
speedBicycle = 0
super.init(speedVehicle: speedBicycle)
self.hasBasket = hasBasket
}
And This
init(){
speedCar = 0
super.init(speedVehicle: speedCar)
}

It makes sense that any Vehicle has an initial speed of either a user desired value, or 0 by default. Same happens with a Car, and since a Car is a Vehicle, you don't need two different speeds.
This would be my refined approach:
import Foundation
class Vehicle: CustomStringConvertible {
var speedInKmH: Double
init(speedInKmH: Double = 0) {
self.speedInKmH = speedInKmH
}
var description: String {
return "Vehicle has \(speedInKmH) km/h speed by default."
}
}
struct GearBox {
var gear: Int
var speedInKmH: Double
}
class Car: Vehicle {
let gearBox: [GearBox] = [GearBox(gear: 1, speedInKmH: 10.5), GearBox(gear: 3, speedInKmH: 33.4), GearBox(gear: 5, speedInKmH: 51.2),
GearBox(gear: 2, speedInKmH: 23.3), GearBox(gear: 4, speedInKmH: 45.0)]
func travelTimeInHoursWith(distanceInKm: Double, gear: Int) -> Double {
if let matchedGearBox = gearBox.filter({ $0.gear == gear }).first {
self.speedInKmH = matchedGearBox.speedInKmH
}
return distanceInKm / speedInKmH
}
override var description: String {
return "My Car has \(self.gearBox.count) gears and has \(self.speedInKmH) km/h speed."
}
}
let toyota = Car()
print(toyota.travelTimeInHoursWith(distanceInKm: 22, gear: 4))
print(toyota)
I did some improvements to make it clear, you can take my code as example and modify your other implemented class/classes

Related

Subclassing Problem: dictionary values from a subclass?

Short Story:
I was trying to make a class whose subclass can have a more specialized member (a dictionary), then I hit the following error:
error: property 'dict' with type '[Int : B]' cannot override a property with type '[Int : A]'
Here is my code:
class A {}
class B: A {} // subclass of A
let dict = [Int:B]()
print(dict is [Int:A]) // true
class MyDict {
var dict = [Int:A]()
}
class MyDict2: MyDict {
/*
⛔ error:
property 'dict' with type '[Int : B]' cannot override a property with type '[Int : A]'
*/
override var dict = [Int:B]()
}
My question is that since an instance of [Int:B] is a [Int:A], why can't we override a dictionary of type [Int:A] with [Int:B] ?
Long Story:
Actually, I was trying to design types for both weighted and unweighted graphs. The following is my implementation:
// unweighted edge
public class Edge<Vertex:Hashable> {
public let start: Vertex
public let end : Vertex
init(from start: Vertex, to end: Vertex) {
self.start = start
self.end = end
}
}
// weighted edge
public class WeightedEdge<Vertex:Hashable, Weight:Comparable> : Edge<Vertex> {
public let weight: Weight
init(from start:Vertex, to end:Vertex, weight:Weight) {
self.weight = weight
super.init(from:start, to:end)
}
}
// unweighted graph (definition)
public class Graph<Vertex:Hashable> {
// edges dictionary
var edgesOf = [Vertex: [Edge<Vertex>]]()
// g.addEdge(from:to:bidirectional:)
public func addEdge(
from start: Vertex,
to end:Vertex,
bidirectional:Bool = false
) {
edgesOf[start, default:[]].append(Edge(from: start, to:end))
if bidirectional {
edgesOf[end, default:[]].append(Edge(from: end, to:start))
}
}
}
// weighted graph (definition)
public class WeightedGraph<Vertex:Hashable, Weight:Comparable> : Graph<Vertex> {
public override func addEdge(from start:Vertex, to end:Vertex, bidirectional:Bool = false) {
fatalError("Can't add an unweighted edge to a weighted graph❗")
}
// g.addEdge(from:to:weight:bidirectional:)
public func addEdge(
from start: Vertex,
to end: Vertex,
weight : Weight,
bidirectional: Bool = false
) {
edgesOf[start, default:[]].append(
WeightedEdge(from: start, to:end, weight:weight)
)
if bidirectional {
edgesOf[end, default:[]].append(
WeightedEdge(from: end, to:start, weight:weight)
)
}
}
}
let g = WeightedGraph<Int,Int>()
g.addEdge(from: 3, to: 4, weight:7, bidirectional: true)
g.addEdge(from: 1, to: 3) // fatalError
It works fine for me, but I'm bothered by the ugly part of it:
public override func addEdge(from start:Vertex, to end:Vertex, bidirectional:Bool = false) {
fatalError("Can't add an unweighted edge to a weighted graph❗")
}
What can I do to prevent a weighted graph from adding an unweighted edge to itself?
When you inherit a class you are including the super class in it so you will get conflicting definitions of the same property, somewhat simplified the compiled version of MyDict2 would be
class MyDict2 {
var dict = [Int:A]()
var dict = [Int:B]()
}
and as you can see this will not work. Alternatively the dict property would be replaced but then you have the problem that any function that accepts a parameter of type MyDict can also take a instance of MyDict2 but if that function accessed the dict property it would find values of type B and the function would have no idea what is since it is defined to take MyDict and therefore only knows about A
I don't think inheritance is the way forward here, alternatives is to have two separate classes that conforms to the same protocol for accessing the underlying storage (dict) or to implement this using generics
class MyDict<T> {
var dict = [Int:T]()
}
let c1 = MyDict<A>()
let c2 = MyDict<B>()

Mutating functions and Properties

I have a struct Town
with a population of 11
struct Town {
var population: Int = 11 {
didSet(oldPopulation){
print("The population has changed to \(population) from \(oldPopulation)")
}
}
}
and I have a mutating function
mutating func changePopulation(amount: Int) {
population += amount
}
I created a zombie class that calls a function that decreases population by 10
final override func terrorizeTown() {
guard var town = town else {
return
}
town.population <= 0 ? print("no people to terrorize") : town.changePopulation(amount: -10)
super.terrorizeTown()
}
when I run this i the main.swift file
var myTown = Town()
var fredTheZombie = Zombie()
fredTheZombie.name = "Fred"
fredTheZombie.town = myTown
//myTown.changePopulation(amount: 0)
print(myTown.population)
fredTheZombie.terrorizeTown()
print(myTown.population)
What I don't understand is the results..
11
The population has changed to 1 from 11
Fred is terrorizing a town!
11
Why is it that when I print (myTown.population) again do i receive a value of 11, when I have called a mutating function on the property. I don't understand.. should the result not be 1, why do i get 11?
It is because the line guard var town = town makes a copy of your Town object. Hence, it is the copy that is mutated.

how to make deinit take effect in swift

I have a Car class. Let's say a car goes to the junkyard, this car should no longer be counted in the total population. I have the deinit function, but how do I systematically remove a car from the car population? In other words, how do I get the deinit to take effect?
I have a class variable isJunk but don't know how to use it to make this work.
class Car {
static var population: Int = 0
var isJunk: Bool = false
var color: String
var capacity: Int
var driver: Bool?
var carOn: Bool = false
init (carColor: String, carCapacity: Int) {
self.capacity = carCapacity
self.color = carColor
Car.population += 1
}
deinit {
Car.population -= 1
}
func startCar() {
self.carOn = true
}
}
class Car {
static var population: Int = 0
init() {
Car.population += 1
}
deinit {
Car.population -= 1
}
}
var cars: [Car] = [Car(), Car()]
print("Population:", Car.population) // "Population: 2"
// now the second car is removed from array and we have no other references to it
// it gets removed from memory and deinit is called
cars.removeLast()
print("Population:", Car.population) // "Population: 1"
However, the same can be achieved just by asking the number of items in cars array. And that's usually a better alternative than a private counter of instances.
To keep the items in memory you will always need some kind of register (e.g. an array) for them. And that register can keep them counted.
One possibility:
class CarPopulation {
var liveCars: [Car] = []
var junkCars: [Car] = []
}
Or you can keep them in one array and set junk on the car and count non-junk cars when needed:
class CarPopulation {
var cars: [Car] = []
func liveCars() -> Int {
return self.cars.filter { !$0.junk }.count
}
}
There are many possibilities but extracting the counters to some other class that owns the cars is probably a better solution.
The deinit is called when you deallocate your instance of Car (when you entirely get rid of the instance of the object). When you put a Car instance in the junkyard I don't think you want to get rid of the instance of Car, you really just want to change its location. I would suggest a different function to handle changing the location of Car.
Perhaps:
func changeLocation(newLocation: String) {
// Perhaps add an instance variable to 'remember' the location of the car
switch newLocation {
case "junkyard":
Car.population -= 1
default:
// Perhaps check whether previous location was Junkyard and increment
// counter if the Car is coming out of the Junkyard
print("Unrecognized location")
}
}

Swift - Changing variable inside struct?

I'm a beginner in Swift and static programming. Going through Big Nerd Ranch Swift book. What I don't understand is why myTown population is changing, but not fredTheZombie.town? The exercise calls for the town population to never go below zero. This could happen when the population is less than 10. How do I change the fredTheZombie.town population variable?
struct Town {
var population = 5422
var numberOfStoplights = 4
func printTownDescription() {
print("Population: \(myTown.population), number of stoplights: \(myTown.numberOfStoplights)")
}
mutating func changePopulation(amount: Int) {
population += amount
}
}
class Monster {
var town: Town?
var name = "Monster"
func terrorizeTown() {
if town != nil {
print("\(name) is terrorizing a town!")
} else {
print("\(name) hasn't found a town to terrorize yet...")
}
}
}
class Zombie: Monster {
var walksWithLimp = true
final override func terrorizeTown() {
guard town?.population > 0 else {
return
}
if town?.population > 10 {
super.town!.changePopulation(-10)
} else {
super.town!.population = 0
}
super.terrorizeTown()
}
func changeName(name: String, walksWithLimp: Bool) {
self.name = name
self.walksWithLimp = walksWithLimp
}
}
var myTown = Town()
myTown.changePopulation(500)
let fredTheZombie = Zombie()
fredTheZombie.town = myTown
fredTheZombie.terrorizeTown()
fredTheZombie.town?.printTownDescription()
fredTheZombie.changeName("Fred the Zombie", walksWithLimp: false)
myTown.changePopulation(-5915)
print(myTown.population)
print(fredTheZombie.town!.population)
fredTheZombie.terrorizeTown()
fredTheZombie.terrorizeTown()
fredTheZombie.town?.printTownDescription()
Output:
Monster is terrorizing a town!
Population: 5922, number of stoplights: 4
7
5912
Fred the Zombie is terrorizing a town!
Fred the Zombie is terrorizing a town!
Population: 7, number of stoplights: 4
Program ended with exit code: 0
Town is a struct, a value type. When assigning a value type to a different variable (e.g. fredTheZombie.town = myTown), that value type is copied (meaning that a new Town is created with the same values as the original Town).
myTown and fredTheZombie.town are not the same town any more. If you want them to be the same instance, make them a class (a reference type).
See more info on Apple Swift Blog and in Swift Language Guide.
The biggest problem we have are optional structs. The result of unwrapping an optional struct (using town!) is again a copy, a new town. To work around that, you have to:
var myTown = super.town!
myTown.changePopulation(-10)
super.town = myTown // assign back
Whole example:
struct Town {
var population = 5422
var numberOfStoplights = 4
func printTownDescription() {
// note you have to print "self" here, not "myTown"
print("Population: \(self.population), number of stoplights: \(self.numberOfStoplights)")
}
mutating func changePopulation(amount: Int) {
population += amount
}
}
class Monster {
var town: Town?
var name = "Monster"
func terrorizeTown() {
if town != nil {
print("\(name) is terrorizing a town!")
} else {
print("\(name) hasn't found a town to terrorize yet...")
}
}
}
class Zombie: Monster {
var walksWithLimp = true
final override func terrorizeTown() {
guard super.town?.population > 0 else {
return
}
var town = super.town!
if town.population > 10 {
town.changePopulation(-10)
} else {
town.population = 0
}
super.town = town
super.terrorizeTown()
}
func changeName(name: String, walksWithLimp: Bool) {
self.name = name
self.walksWithLimp = walksWithLimp
}
}
In your case there is no need for town to be actually optional. You could just pass it to Monster in a constructor.

Limits of Protocol Extensions and defaults in swift2

So I was playing around with protocol extensions and i ran into an "interesting" problem.
I wanted to write a Meters and Kilometers units type for testing some things out. Its VERY easy to do this as a class where there is a base class and both sub classes override the base, while just overriding a simple value
//Conversion factor between types
enum DISTANCE_UNIT_TYPE : Double {
case METER = 1.0;
case KILOMETER = 0.001;
}
protocol DistanceUnit {
var unitType : DISTANCE_UNIT_TYPE {get}
var value : Double { get set }
var baseValue : Double { get set }
}
struct Kilometers : DistanceUnit {
var unitType = DISTANCE_UNIT_TYPE.KILOMETER
var value : Double
var baseValue : Double
init(_ v : Double) {
value = v
baseValue = v * unitType.rawValue
}
}
struct Meters : DistanceUnit {
var unitType = DISTANCE_UNIT_TYPE.METER
var value : Double
var baseValue : Double
init(_ v : Double) {
value = v
baseValue = v * unitType.rawValue
}
}
So as you can see i have lots of duplicate code (specifically the initializers)
I tried to make a protocol extension to set the default initializer
extension DistanceUnit {
init(_ v : Double) {
value = v
baseValue = v * unitType.rawValue
}
}
but I get an error of variable 'self' passed by reference before being initalized
Is there any way to get this to work or do i just have to type lots of duplicate code? Maybe using unsafe or something?
I assume that fqdn is right and we won't be able to use custom inits inside protocols extension as we would like to, but only time will tell.
But there is still some workaround:
struct Meters : DistanceUnit {
var unitType = DISTANCE_UNIT_TYPE.METER
var value : Double
var baseValue : Double
init() { // this one is needed as designated initializer for your protocol extension
value = 0
baseValue = 0
}
}
protocol DistanceUnit {
var unitType : DISTANCE_UNIT_TYPE {get}
var value : Double { get set }
var baseValue : Double { get set }
init() // this is new and you will NEED to implement this in your structure or class
}
extension DistanceUnit {
init(_ v : Double) {
self.init()
value = v
baseValue = v * unitType.rawValue
}
// you can now implement a lot more different default inits and they should work fine here :)
// here is a quick example
init(_ s : String) {
self.init(Double(s.characters.count))
}
}
Hope that will help you. I learned this trick a few days ago when i was building a custom generic singleton generator with protocol extensions (see here).