Swift - how to store a struct instance in a class propriety - swift

I am very new to Swift so I apologize upfront if this is a "dumb" question. I am just working on a playgrounds script for generating random items, in this case, weapons. When I run my code I get this error: error: Execution was interrupted, reason: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0). What I was trying to do is hold an instance of a structure(which is handle) in my class normalBladeType in variable weaponHandle. I've tried researching about this topic but I've yet to find an answer. Any suggestions would be great. For all I know I may be going about this all wrong.
Thanks,
my code:
//: Playground - noun: a place where people can play
import Cocoa
let handleWoods = ["White Ash", "Oak", "White Oak", "Elm", "Maple","Walnut", "Cherry", "Rosewood", "Ash", "Hickory", "Birch", "Hemlock", "Cedar", "Pine"]
let handleGrips = ["Leather", "Buckskin", "Sharkskin", "Goat Skin", "Deerskin", "Elk Skin", "Rayskin", "Snakeskin", "Silk Cord", "Cotton Cord"]
let gripQualities = ["Simple", "Interwoven", "Ornate", "Smooth", "Thin", "Thick", "Ruff", "Worn"]
func returnRandomItem( _ list: [Any])-> Any {
return list[Int(UInt32(list.count))]
}
struct handle {
var name: String
var value, grip: Int
var weight: Double
var withGrip: Bool
init(withGrip: Bool) {
self.weight = 0.25
self.withGrip = withGrip
let handleNameWithWood = "\(returnRandomItem(handleWoods)) Handle"
if self.withGrip {
let randGrip = "\(returnRandomItem(gripQualities)) \(returnRandomItem(handleGrips)) Grip)"
self.name = "\(randGrip) (\(handleNameWithWood))"
self.grip = 75
self.value = 2
} else {
self.name = handleNameWithWood
self.grip = 50
self.value = 1
}
}
func description() {
print("Handle Description \(self.name)")
}
}
class weapon {
var TypeOfWeapon: String
var weaponHandle: handle
init(weaponType: String, doesHaveGrip: Bool) {
self.TypeOfWeapon = weaponType
self.weaponHandle = handle(withGrip: doesHaveGrip)
}
}
class normalBladeType: weapon {
init() {
super.init(weaponType: "normalBladeType", doesHaveGrip: false)
}
func description() {
print("TypeOfWeapon: \(self.TypeOfWeapon)")
print("TypeDescription: normal hilt (guard - handle - pommel) + straight blade")
}
}
var foo = normalBladeType()
foo.description()

Your returnRandomItem function is wrong. You should change it to
func returnRandomItem( _ list: [Any])-> Any {
let index: UInt32 = arc4random_uniform(UInt32(list.count))
return list[Int(index)]
}
It is working fine for me with this code.

Related

Converting app from SQLite.swift to GRDB.swift Second Question

I am continuing the conversion of a number of my apps from SQLite.sift to GRDB.swift.
I converted my structs to add Codable, FetchableRecord so as to have them work better with GRDB. This was suggested in a reply to my first post on this subject.
struct FigureList: Codable, FetchableRecord
{
let figID: Int64
var notes: String?
var theDescription: String
var obrienNum: String
var manufNum: String?
var catagory: String?
}
This is the piece of code I'm looking for help to redo so it will work with GRDB. My apps use this type of code to build arrays from the database table. Pretty standard process.
static func getFigureList() -> [FigureList]
{
var theArray = [FigureList]()
let theTable = Table(gTheCollection)
let figID = Expression<Int64>("FigureID")
let notes = Expression<String>("Notes")
let theDescription = Expression<String>("theDescription")
let obrienNum = Expression<String>("ObrienNum")
let manufNum = Expression<String>("ManufNum")
let theCatagory = Expression<String>("Category")
do {
for figures in try Database.shared.databaseConnection!.prepare(theTable.order(obrienNum)) {
theArray.append(FigureList(figID: figures[figID],
notes: figures[notes],
theDescription: figures[theDescription],
obrienNum: figures[obrienNum],
manufNum: figures[manufNum],
catagory: figures[theCatagory]))
}
} catch {
print("Fetching figure list failed: \(error)")
}
return theArray
}
This is what I have come up with so far. It doesn't produce any warnings or errors but then again I'm pretty sure it's not total correct. Again, thanks in advance for any help.
static func getFigList() -> [FigureList]
{
var theArray = [FigureList]()
let theTable = gTheCollection
let figID = Column("FigureID")
let notes = Column("Notes")
let theDescription = Column("theDescription")
let obrienNum = Column("ObrienNum")
let manufNum = Column("ManufNum")
let theCatagory = Column("Category")
do {
try Database.shared.databaseConnection!.read { db in
let figures = try Row.fetchOne(db, sql: "SELECT * FROM = ? ORDER BY ObrienNum", arguments: [theTable])
theArray.append(FigureList.init(figID: figures![figID],
notes: figures![notes],
theDescription: figures![theDescription],
obrienNum: figures![obrienNum],
manufNum: figures![manufNum],
catagory: figures![theCatagory]))
}
} catch {
print("Fetching figure list failed: \(error)")
}
return theArray
}
I converted my structs to add Codable, FetchableRecord so as to have them work better with GRDB.
Good. Now it's very simple:
static func getFigList() throws -> [FigureList] {
return try Database.shared.databaseConnection!.read { db in
// SELECT * FROM FigureList ORDER BY ObrienNum
return FigureList.order(Column("ObrienNum")).fetchAll(db)
}
}

Using an enum to set a property during initialization in swift

I'd like to learn how to set a unique gifted dance property during initialization using a breakdances enum that uses strings. I figured it would work but when I tried different variations of setting the property in init, I would get compile errors such as "assigning a property to itself" and many others. I've run out of ideas but I know its possible because some Cocoa classes do this during initialization such as UITableView when selecting preferred style.
import Foundation
enum Breakdances: String {
case HoppityHop = "Hop Hop Hop and two step is what I do usually"
case Greyjoy = "I made up this dance, pretty cool huh?"
case ButtSwirl = "Let's do the butt swril"
case PsychMovementWithHands = "Psych, Psych, Psych! Psych"
case TheDab = "Dabbbbb!"
case TheBump = "I'm doing the rump bump dance"
}
class Monkeys: Animals, canPlayAroundProtocol, randomJungleActivity {
static var monkeysPopulation: Int = 0
var uniqueGiftedDance: Breakdances
override init(name:String){
super.init(name: name)
self.uniqueGiftedDance = uniqueGiftedDance
Monkeys.monkeysPopulation += 1
}
override func makeSound() -> String {
energyLevel -= 4
return "Ah ah ah"
}
override func eatFood(){
energyLevel += 2
}
override func sleep(){
}
func play(){
let reducedEnergy = energyLevel - 8
if reducedEnergy < 0 {
print("\(name) is too tired, I don't have enough energy")
}else {
print("Oooo Oooo Oooo")
print("\(name)'s energy level is now \(reducedEnergy)")
}
}
func startUniqueJungleAct(){
print(uniqueGiftedDance)
print("Swinging from a tree and throwing banannas")
}
deinit {
Monkeys.monkeysPopulation -= 1
}
}
Here is my parent class:
import Foundation
protocol canPlayAroundProtocol {
func play()
}
protocol randomJungleActivity {
func startUniqueJungleAct()
}
class Animals {
static var animalPopulation: Int = 0
var name: String!
var energyLevel: Int = 100
init(name: String) {
self.name = name
Animals.animalPopulation += 1
print("Another animal has given birth, animal population is now \(Animals.animalPopulation)")
}
func makeSound() -> String{
energyLevel -= 3
return "null"
}
func eatFood() {
energyLevel += 5
}
func sleep(){
energyLevel += 10
}
static func junglePerformSoundOff(){
}
func bathroomSound(){
}
deinit {
Animals.animalPopulation -= 1
}
}
You just need to add a new parameter to your initializer.
init(name: String, uniqueGiftedDance: Breakdances) {
super.init(name: name)
self.uniqueGiftedDance = uniqueGiftedDance
Monkeys.monkeysPopulation += 1
}

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.

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)

Swift generic cast to Protocol fails with swift_dynamicCastUnknownClass

The following example is taken from Apple Swift Reference guide. I only added the getHasAreaInstances() and getGenericHasAreaInstances()
import UIKit
#objc protocol HasArea {
var area: Double { get }
}
#objc protocol HasExtendedArea: HasArea {
var extendedArea: Double { get }
}
class Circle: HasArea {
let pi = 3.1415927
var radius: Double
var area: Double { return pi * radius * radius }
init(radius: Double) { self.radius = radius }
}
class Country: HasArea {
var area: Double
init(area: Double) { self.area = area }
}
class Continent: HasExtendedArea {
var area: Double { return 300 }
var extendedArea: Double { return 3000 }
}
let objects: [HasArea] = [
Circle(radius: 2.0),
Country(area: 243_610),
Continent()
]
for object in objects {
if let objectWithArea = object as? HasExtendedArea {
println("Extended Area is \(objectWithArea.area)")
} else {
println("Area is not extended")
}
}
// Extended Area is 300.0
// Area is not extended
// Area is not extended
The method below returns the correct array:
func getHasExtendedAreaInstances() -> [HasExtendedArea] {
var haveArea: [HasExtendedArea] = []
for object in objects {
if let objectWithArea = object as? HasExtendedArea {
haveArea.append(objectWithArea)
}
}
return haveArea
}
let areas = getHasExtendedAreaInstances()
//[Continent]
The method below returns the correct array:
func getGenericHasExtendedAreaInstances<T>() -> [T] {
var haveArea: [T] = []
for object in objects {
if let objectWithArea = object as? T {
haveArea.append(objectWithArea)
}
}
return haveArea
}
let areasGeneric: [HasExtendedArea] = getGenericHasExtendedAreaInstances()
//[Continent]
However, as soon as a constraint is imposed on the generic type, it no longer works
func getGenericConstraintHasExtendedAreaInstances<T: HasArea>() -> [T] {
var haveArea: [T] = []
for object in objects {
if let objectWithArea = object as? T {
// the line above fails with swift_dynamicCastUnknownClass
haveArea.append(objectWithArea)
}
}
return haveArea
}
let areasGenericConstraint: [HasExtendedArea] = getGenericConstraintHasExtendedAreaInstances()
Your generic function makes no sense. What would resolve it? What would satisfy it? Make a simpler example with the same basic declaration structure: it's an impossible function. For example, start with this nongeneric function:
class Thing : Printable {
var description : String {return "thing"}
}
func g() -> [Thing] {
return [Thing()]
}
let result : [Thing] = g()
Now modify g to be generic, exactly parallel to your function:
class Thing : Printable {
var description : String {return "thing"}
}
func g<T:Printable>() -> [T] {
return [Thing()]
}
let result : [Thing] = g()
It doesn't compile - because it makes no sense.
This is fixed in Swift 1.2, tested on Xcode 6.3 Beta 3
You can specify the type constraint without swift compiler failing on you