environment XCode 6.4 Swift 2.something
I have two simple Custom Classes
class Stock {
var ageArray = [3,6,9,12,15,18,24,30,36,42,48,54,60,66,72] // in months
var beastArray = ["Angus","Braford","Charolais","Droughtmaster","Euro","Hereford"]
var breedArray = ["Calves","Vealers","Weaners","Heifers","Steers","Cows","Bulls"]
var priceArray = [600.00,650.00,700.00,750.00,800.00,850.00,900.00,950.00,1000.00,]
}
and
class Sale {
var age : Int = 0
var beast : String = " "
var breed : String = " "
var price : Double = 0.00
}
Now to my view controller
I've instantiated a report from Sale Class. The ViewController holds an array of all those reports as I'm taught in nuremous places, declaring it first and instatiating it in viewDidLoad
class ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {
@IBOutlet weak var picker: UIPickerView!
var report = Sale()
var sheets = Stock()
var saleArray : [Sale] = [] // declaration
override func viewDidLoad() {
super.viewDidLoad()
saleArray = [Sale]() // instantiating
}
the other delegate functions of the picker work sweetly, no need to show them all here, but this is where the two class Objects meet to pass values
func pickerView(picker: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
switch(component) {
case 0:
report.breed = sheets.breedArray[row]
break
case 1:
report.beast = sheets.beastArray[row]
break
case 2:
report.age = sheets.ageArray[row]
break
default:
report.price = sheets.priceArray[row]
break
}
}
and an onscreeen button loads them into an array
@IBAction func AcceptValues(sender:UIButton) {
saleArray.append(report)
}
that's all there is to it.
This is the result as seen in the debugger with a breakpoint set as below after 3 times around with [0] supposed to have Angus Calves and [1] having Droughtmaster Heifers
so the question is why would the saleArray be filling up with n instances of whatever was last entered? I know i'm not looking at the last entry n times. But curiously the address for report is all the same at 7A19C000.
I thought it might be the compiler can't infer the array type after the instatiaton in viewDidLoad. Examining various tutorials and the code supplied with them treats the matter more or less as I have above. Which is the reason for the title, I'm sure Swift can hold an array of objects other than the usuals.
I've even gone to the expense at purchasing not one, but two of Matt Neuberg's books just to check on how to set up an Object Array, but like all the material available they just discuss arrays of Int and Double and String and no more. Sometimes the most infuriating bugs are the most staring-at-you-in-your-face, and I've been chasing this for close on a week.
There's little else to it the code.
EDIT: thanks to the two contributors below, the comments show what i did to make it work. But I have a feeling its not elegant: I also made Stock a struct.
class ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {
@IBOutlet weak var picker: UIPickerView!
@IBOutlet weak var textPanel: UITextView!
var sheets = Stock()
var saleArray : [Sale] = []
var localBreed = " " // introduced some handover values
var localBeast = " " // because report is out of scope
var localAge = 0 // in the picker functions
var localPrice = 0.00
. . .
@IBAction func AcceptValues(sender:UIButton) {
var report = Sale() // new reports instantiated here
report.breed = localBreed // and locals handover values to
report.beast = localBeast // report instance before adding
report.age = localAge // to array
report.price = localPrice
saleArray.append(report)
}
. . .
func pickerView(picker: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
switch(component) {
case 0:
localBreed = sheets.breedArray[row]
break
case 1:
localBeast = sheets.beastArray[row]
break
case 2:
localAge = sheets.ageArray[row]
break
default:
localPrice = sheets.priceArray[row]
break
}
}
I believe that it is because report
is a single instance of Sale
. Therefore each time you select a new combination - you are not creating a new Sale
item, rather you are changing the values associated with that single instance of Sale
called report
. When you press the button it adds another reference to that single report
instance.
These class objects are passed by reference - i.e. when you add report
to the saleArray
it is not creating a copy of the values - rather you are passing a reference to the actual instance. Each time you press the button you are adding a reference to the same instance of Sale
. And the values associated with that instance are then getting changed when you use the picker. It's the same instance over and over.
You would need to change your code so that you create a new instance of Sale
for each selection. As a quick hack, to test this, you could add code to your button which creates a new Sale
instance based on the selected values - and then adds that to saleArray
.
ETA - one other thing I noticed: You are instantiating saleArray
twice - both at //declaration
and in viewDidLoad()
. Although that is not causing the issue you have described, it could cause an issue under potential circumstances.