Overriding custom init from super class - swift

I am trying to override custom init in my code as you can see I am creating Player class with default and custom init
class Player{
//Properties
var name : String
var score : Int
//Methods
func description() -> String{
return( "Player \(name) has score \(score)")
}
//Default Initiallizer
init(){
name = "Sohrab"
score = 0
}
//Custom Initializer
init(name : String, score : Int){
self.name = name
self.score = score
}
}
and below I create PremierPlayer class
class PremierPlayer : Player {
//Properties
var memberLevel : String
//Method
override func description() -> String {
let originalMessage = super.description()
return ("\(originalMessage) is a \(memberLevel)")
}
//Default Initilizer
override init() {
memberLevel = "Gold"
super.init()
}
//Custome Initilizer
init(name: String, score: Int, memberLevel:String) {
self.memberLevel = memberLevel
super.init(name: <#String#>, score: <#Int#>)
}
}
In Line super.init(name: <#string#>, score: <#Int#>) i got an error ISSUE expected ',' separator
What should I do?

The formatting of your (current version of) question is rather confusing, but if you are talking about this line:
super.init(name: <#String#>, score: <#Int#>)
... then you should replace <#String#> with just value of String and <#Int#> with Int types. Those <#...#> are placeholders that XCode injects into code automatically for you to replace them with something sensible.

Related

How to assign a value to optional property of class

I've tried a bunch of different ways to assign a value to stepperValue to no avail. I get my Offence model filled through Firebase and I simply want to "assign" a stepper value to each offences so that I can make calculations i.e points X stepperValue .
Model swift file:
class Offence : Comparable {
var section: String
var name: String
var cost: Int
var points: Int
var stepperValue: Double?
init(section: String, name: String, cost: Int, points: Int) {
self.section = section
self.name = name
self.cost = cost
self.points = points
}
class Variables {
static var selectedOffencesArray: [Offence] = [Offence]()
}
This one is in its own TableViewCell class in its own swift file
#IBAction func stepperValueChanged(_ sender: Any) {
for offence in Variables.selectedOffencesArray {
offence.stepperValue! = 3.0
}
The following just work
for offence in Variables.selectedOffencesArray {
offence.stepperValue = 3.0 // << no force (!) needed
}

Swift Initializers and Class Inheritance

I just wanted to ask why does this code print out the quantity 1 even though the RecipeIngredient doesn't provide a default value:
class Food {
var name: String
init(name: String) {
self.name = name
}
convenience init() {
self.init(name: "[Unnamed]")
}
}
class RecipeIngredient: Food {
var quantity: Int
init(name: String, quantity: Int) {
self.quantity = quantity
super.init(name: name)
}
override convenience init(name: String) {
self.init(name: name, quantity: 1)
}
}
class ShoppingListItem: RecipeIngredient {
var purchased = false
var description: String {
var output = "\(quantity) x \(name)"
output += purchased ? " ✔" : " ✘"
return output
}
}
let item = ShoppingListItem()
print(item.quantity)
The default value is provided by the convenience initializer of RecipeIngredient.
ShoppingListItem() is shorthand for
ShoppingListItem.init() (inherited from `Food) which calls
ShoppingListItem.init(name:) (inherited RecipeIngredient) which calls
ShoppingListItem.init(name: name, quantity: 1) (inherited RecipeIngredient) which calls
ShoppingListItem.init(name: String, quantity: Int) (inherited RecipeIngredient) which ultimately sets quantity to 1
This is some pretty basic debugging. You should really look into how to use the Xcode debugger.

Swift: The proper way to initialize model class with a lot of properties

How do you initialize your classes/structs with a lot of properties?
This question could probably be asked without Swift context but Swift brings a flavour to it, so I add Swift tag in headline and tags.
Let's say you have a User class with 20 properties. Most of them should not be nil or empty. Let's assume these properties are not interdependent. Let's assume that 33% of it should be constant (let) by the logic of the class. Let's assume that at least 65% of them do not have meaningful default values. How would you design this class and initialize an instance of it?
So far I have few thoughts but none of it seems to be completely satisfactory to me:
put all of the properties linearly in the class and make huge init method:
class User {
// there is 20 properties like that
let id : String
let username : String
let email : String
...
var lastLoginDate : Date
var lastPlayDate : Date
// then HUUUUGE init
init(id: String,
username: String,
...
lastPlayDate: Date) {
}
}
try to group properties into sub types and deal with smaller inits separately
class User {
struct ID {
let id : String
let username : String
let email : String
}
struct Activity {
var lastLoginDate : Date
var lastPlayDate : Date
}
let id : ID
...
var lastActivity : Activity
// then not so huge init
init(id: ID,
...
lastActivity: Activity) {
}
}
another solution is to break requirements a bit: either declare some of the properties optional and set values after init or declare dummy default values and set normal values after init, which conceptually seems to be the same
class User {
// there is 20 properties like that
let id : String
let username : String
let email : String
...
var lastLoginDate : Date?
var lastPlayDate : Date?
// then not so huge init
init(id: String,
username: String,
email: String) {
}
}
// In other code
var user = User(id: "1", username: "user", email: "user#example.com"
user.lastLoginDate = Date()
Is there a nice paradigm/pattern how to deal with such situations?
You can try the builder pattern.
Example
class DeathStarBuilder {
var x: Double?
var y: Double?
var z: Double?
typealias BuilderClosure = (DeathStarBuilder) -> ()
init(buildClosure: BuilderClosure) {
buildClosure(self)
}
}
struct DeathStar : CustomStringConvertible {
let x: Double
let y: Double
let z: Double
init?(builder: DeathStarBuilder) {
if let x = builder.x, let y = builder.y, let z = builder.z {
self.x = x
self.y = y
self.z = z
} else {
return nil
}
}
var description:String {
return "Death Star at (x:\(x) y:\(y) z:\(z))"
}
}
let empire = DeathStarBuilder { builder in
builder.x = 0.1
builder.y = 0.2
builder.z = 0.3
}
let deathStar = DeathStar(builder:empire)
Example taken from here: https://github.com/ochococo/Design-Patterns-In-Swift
If you are looking for a bit more Java like solution, you can try something like this.
Alternative Example
final class NutritionFacts {
private let servingSize: Int
private let servings: Int
private let calories: Int
private let fat: Int
private let sodium: Int
private let carbs: Int
init(builder: Builder) {
servingSize = builder.servingSize
servings = builder.servings
calories = builder.calories
fat = builder.fat
sodium = builder.sodium
carbs = builder.carbs
}
class Builder {
let servingSize: Int
let servings: Int
private(set) var calories = 0
private(set) var fat = 0
private(set) var carbs = 0
private(set) var sodium = 0
init(servingSize: Int, servings: Int) {
self.servingSize = servingSize
self.servings = servings
}
func calories(value: Int) -> Builder {
calories = value
return self
}
func fat(value: Int) -> Builder {
fat = value
return self
}
func carbs(value: Int) -> Builder {
carbs = value
return self
}
func sodium(value: Int) -> Builder {
sodium = value
return self
}
func build() -> NutritionFacts {
return NutritionFacts(builder: self)
}
}
}
let facts = NutritionFacts.Builder(servingSize: 10, servings: 1)
.calories(value: 20)
.carbs(value: 2)
.fat(value: 5)
.build()
Example taken from: http://ctarda.com/2017/09/elegant-swift-default-parameters-vs-the-builder-pattern

Error:Missing argument for parameter 'makePetMakeNoise' in call

Hi I am doing some Swift coding and I cant figure out how to get rid of this error:
Missing argument for parameter 'makePetMakeNoise' in call.
Could you help me fix this error?
import Foundation
import UIKit
class Human {
static var numCreated:Int = 4
var name:String = ""
var pet:Pet
init(name:String,pet:Pet){
self.name = name
self.pet = pet
Human.numCreated++
}
func makePetMakeNoise(){
var randomNumber = arc4random_uniform(9)
self.pet.makeNoise(randomNumber) //Missing argument for parameter 'makePetMakeNoise' in call
}
func feedPet(){
self.pet.eat
}
static func populationCount(){
println("Total population count is \(Human.numCreated)")
}
}
class Pet {
var name:String = ""
var noise:String = ""
var canMakeNoise:Bool = true
init(name:String,noise:String,canMakeNoise:Bool){
self.name = name
self.noise = noise
self.canMakeNoise = canMakeNoise
}
func makeNoise(canMakeNoise: Int, makePetMakeNoise: Int){
if self.canMakeNoise {
for _ in 1...5{
println("\(self.name) \(self.noise)")
}
}else {
println("\(self.name) *remains silent*")
}
}
func eat(){
println("\(name) is eating")
}
class Dog:Pet{
}
class Cat:Pet{
override func eat {
super.eat()
println("I'm still hungry, meow")
}
}
}
//Pets
var Tobie = Pet(name: "Tobie", noise: "Bark", canMakeNoise: true)
var Bud = Pet(name: "Bud", noise: "Bark", canMakeNoise: false)
var Ginger = Pet(name: "Ginger", noise: "bark", canMakeNoise: false)
var Curry = Pet(name: "Curry", noise: "Bark", canMakeNoise: true)
//Humans
var Sam = Human(name: "Sam", pet: Tobie)
var Mark = Human(name: "Mark", pet: Bud)
var Spencer = Human(name: "Spencer", pet: Ginger)
var Jessie = Human(name: "Jessie", pet: Curry)
let Humans = [Sam, Mark, Spencer, Jessie]
for Human in Humans {
println("\(Humans) \(feedPet) \(makePetMakeNoise)") //Use of unresolved identifier 'feedPet and makePetMakeNoise'\\
}
`
Your makeNoise method defined for Pet takes two parameters. Problem is that when you call it in the line that gives you the error, you pass it just one parameter.
Possible solution is:
Change the Pet's method as follow:
func makeNoise(makePetMakeNoise: Int){
if self.canMakeNoise {
for _ in 1...5{
println("\(self.name) \(self.noise)")
}
}else {
println("\(self.name) *remains silent*")
}
}
Update the code that gives you the error in Human like this:
func makePetMakeNoise(){
var randomNumber = Int(arc4random_uniform(9))
self.pet.makeNoise(randomNumber)
}
Notice I convert random to Int since this is the expected parameter type.
Please consider I'm just guessing a possible modification since I don't know what your classes are intended for ... maybe just a playground.
Other solution is effectively passing two parameters when you call the pet's method from human.
Hope this helps
Your function func makeNoise(canMakeNoise: Int, makePetMakeNoise: Int) expects two arguments, but your are only passing the one randonNumber in your call self.pet.makeNoise(randomNumber). It should look something like this: self.pet.makeNoise(randomNumber, someOtherNumber)

Access properties via subscripting in Swift

I have a custom class in Swift and I'd like to use subscripting to access its properties, is this possible?
What I want is something like this:
class User {
var name: String
var title: String
subscript(key: String) -> String {
// Something here
return // Return the property that matches the key…
}
init(name: String, title: String) {
self.name = name
self.title = title
}
}
myUser = User(name: "Bob", title: "Superboss")
myUser["name"] // "Bob"
Update: The reason why I'm looking for this is that I'm using GRMustache to render from HTML templates. I'd like to be able to just pass my model object to the GRMustache renderer…
GRMustache fetches values with the keyed subscripting objectForKeyedSubscript: method and the Key-Value Coding valueForKey: method. Any compliant object can provide values to templates.
https://github.com/groue/GRMustache/blob/master/Guides/view_model.md#viewmodel-objects
This is a bit of a hack using reflection. Something along the lines of the following could be used.
protocol PropertyReflectable { }
extension PropertyReflectable {
subscript(key: String) -> Any? {
let m = Mirror(reflecting: self)
for child in m.children {
if child.label == key { return child.value }
}
return nil
}
}
struct Person {
let name: String
let age: Int
}
extension Person : PropertyReflectable {}
Then create a Person and access it's keyed properties.
let p = Person(name: "John Doe", age: 18)
p["name"] // gives "John Doe"
p["age"] // gives 18
You could modify the subscript to always return an interpolated string of the property value.
Adding some syntax sugar to Benzi's answer:
protocol PropertyReflectable { }
extension PropertyReflectable {
subscript(key: String) -> Any? {
let m = Mirror(reflecting: self)
return m.children.first { $0.label == key }?.value
}
}
struct Person: PropertyReflectable {
let name: String
let age: Int
}
Then create a Person and access it's keyed properties.
let p = Person(name: "John Doe", age: 18)
p["name"] // gives "John Doe"
p["age"] // gives 18
Using valueForKey should enable you to access properties using their names. Be sure that you're working with a object that inherit NSObject
class people: NSObject {
var age: NSString = "44"
var height: NSString = "153"
}
let person:people = people()
let stringVariable = "age"
person.valueForKey("age")
// Print "44"
person.valueForKey("\(stringVariable)")
// Print "44"
(GRMustache author here)
Until a swift-oriented Mustache library is out, I suggest having your classes inherit from NSObject (so that they have the valueForKey: method). GRMustache will then fetch values with this method.
In case this would still not work (blank values in the rendering), you may try to disable GRMustache security features (see https://github.com/groue/GRMustache/blob/master/Guides/security.md#disabling-safe-key-access)
Should you experience any other trouble, please open an issue right into the repository: https://github.com/groue/GRMustache/issues
EDIT February 2, 2015: GRMustache.swift is out: http://github.com/groue/GRMustache.swift
Shim's answer above doesn't work anymore in Swift 4. There are two things you should be aware of.
First of all, if you want to use value(forKey:) function, your class must inherit NSObject.
Secondly, since Objective-C doesn't know anything about value type, you have to put the #objc keyword in front of your value type properties and Swift will do the heavy-lifting for you.
Here is the example:
import Foundation
class Person: NSObject {
#objc var name: String = "John Dow"
#objc var age: Int = 25
#objc var height: Int = 180
subscript(key: String) -> Any? {
return self.value(forKey: key)
}
}
let person: Person = Person()
person["name"] // "John Dow"
person["age"] // 25
person["height"] // 180
I suppose you could do:
class User {
let properties = Dictionary<String,String>()
subscript(key: String) -> String? {
return properties[key]
}
init(name: String, title: String) {
properties["name"] = name
properties["title"] = title
}
}
Without knowing your use case I would strongly advise against doing this.
Another approach:
class User {
var name : String
var title : String
subscript(key: String) -> String? {
switch key {
case "name" : return name
case "title" : return title
default : return nil
}
}
init(name: String, title: String) {
self.name = name
self.title = title
}
}
It might be worth noting that Swift doesn't appear to currently support reflection by names. The reflect function returns a Mirror whose subscript is Int based, not String based.