object 类型的变量作为数组行为不当

variable of object type as an Array misbehaving

环境XCode6.4Swift2.something

我有两个简单的自定义 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,]
}

class Sale {
    var age  : Int = 0
    var beast : String = " "
    var breed : String = " "
    var price : Double = 0.00
}

现在到我的视图控制器

我已经实例化了来自 Sale Class 的报告。 ViewController 包含所有这些报告的数组,正如我在许多地方所教的那样,首先声明它并在 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
    }

选择器的其他委托函数工作得很好,不需要在这里展示它们,但这是两个 class Object 相遇传递值的地方

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
    }
}

屏幕上的按钮将它们加载到数组中

@IBAction func AcceptValues(sender:UIButton) {

    saleArray.append(report)
}

仅此而已。

这是在调试器中看到的结果,断点设置如下 3 次后 [0] 应该有 Angus Calves 和 [1] 有 Droughtmaster Heifers

所以问题是为什么 saleArray 会填满 n 个最后输入的实例?我知道我不是在看最后一个条目 n 次。但奇怪的是,报告地址都是7A19C000。

我认为可能是viewDidLoad中instatiaton后编译器无法推断数组类型。检查各种教程和随附的代码或多或少地处理了我在上面所做的事情。这就是标题的原因,我确定 Swift 可以容纳一个 objects 的数组,而不是通常的数组。

我什至花钱买了两本 Matt Neuberg 的书,只是为了检查如何设置 Object 阵列,但就像所有可用的 material他们只讨论 Int 和 Double 和 String 的数组,仅此而已。有时最令人恼火的错误是最多的 staring-at-you-in-your-face,我已经追查了将近一个星期。

代码没有其他内容。


编辑: 感谢下面的两位贡献者,评论显示了我为使其工作所做的工作。但我觉得它不优雅: 我还把 Stock 做了一个结构体。

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
    }
}

我认为这是因为 reportSale 的一个实例。因此,每次您 select 一个新的组合 - 您并不是在创建一个新的 Sale 项目,而是在更改与名为 reportSale 的单个实例关联的值。当您按下按钮时,它会添加对该单个 report 实例的另一个引用。

这些 class 对象通过引用传递 - 即当您将 report 添加到 saleArray 时,它不会创建值的副本 - 而是将引用传递给实际实例。每次按下按钮时,您都会添加对 Sale 的同一实例的引用。当您使用选择器时,与该实例关联的值就会发生变化。这是一遍又一遍的相同实例。

您需要更改代码,以便为每个 selection 创建一个新的 Sale 实例。作为快速破解,要对此进行测试,您可以将代码添加到您的按钮,该按钮根据 selected 值创建一个新的 Sale 实例 - 然后将其添加到 saleArray.

ETA - 我注意到的另一件事:您正在实例化 saleArray 两次 - 在 //declarationviewDidLoad() 中。虽然这不会导致您描述的问题,但在潜在情况下可能会导致问题。