Делегат Pickerview UIView: индекс массива вне диапазона

Я создал представление выбора с двумя компонентами с другим источником данных:

func pickerView(pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusingView view: UIView?) -> UIView {
    let pickerLabel = UILabel()
    let titleLabel = firstFieldArray[row]
    let titlelabel2 = secondFieldArray[row]

    if component == 0 {
    let myTitle = NSAttributedString(string: titleLabel, attributes: [NSFontAttributeName:UIFont(name: "Georgia", size: 15.0)!,NSForegroundColorAttributeName:UIColor.blackColor()])
    pickerLabel.attributedText = myTitle
    } else {
        let myTitle = NSAttributedString(string: titlelabel2, attributes: [NSFontAttributeName:UIFont(name: "Georgia", size: 15.0)!,NSForegroundColorAttributeName:UIColor.blackColor()])
        pickerLabel.attributedText = myTitle
    }
    return pickerLabel
}

это моя модель данных:

class professionArrays {
    func professsionValues() -> [String] {

        return ["Engineer", "Information Technology", "Teacher"]
    }

    func subProfessionValues(profession: String) -> [String] {
        if profession == "Engineer" {
            return ["Electrical Engineer","Sex Engineer","Civil Engineer","Software Engineer"]
        } else if profession == "Information Technology" {
            return ["IT Programmer","UI/UX Designer","Tester/Debugger"]
        } else {
            return ["English Teacher", "Math Teacher", "Physics Teacher"]
        }

    }
}

В представлении выбора отображаются массивы, когда я выбираю «Инженер», «Информационные технологии» и «Учитель», они показывают их субпрофессиональные значения во втором компоненте.

Ошибка возникает, например, когда я выбираю «Информационные технологии» и выбираю «Инженер» в первом компоненте, а когда я перемещаю значение второго компонента, возникает ошибка:

ошибка: фатальная ошибка: индекс массива вне допустимого диапазона

редактировать: код внутри делегата didSelectRow

func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
    if component == 0 {
        let professionAndSubProfession = professionArrays()
        let currentValue = firstFieldArray[row]
        secondFieldArray = professionAndSubProfession.subProfessionValues(currentValue)
        pickerView.reloadAllComponents()
        firstProfessionCurrentValue = firstFieldArray[row]
        print(firstProfessionCurrentValue)
        selectedProfessionLabel.text = firstProfessionCurrentValue
        professionTextfield.text = firstProfessionCurrentValue


    } else {

        secondSubProfessionCurrentValue = secondFieldArray[row]
        selectedSubProfessionLabel.text = secondSubProfessionCurrentValue
        professionTextfield.text = "\(firstProfessionCurrentValue!) - \(secondSubProfessionCurrentValue!)"
        print(secondSubProfessionCurrentValue)
        pickerView.reloadAllComponents()

    }

}

person suisied    schedule 16.09.2015    source источник
comment
Вы перезагружаете второй компонент при изменении выбранного значения первого компонента?   -  person Larme    schedule 16.09.2015
comment
@Larme да, это работает, когда я использую делегат attributeTitleForRow. Я прокомментировал делегат и использовал повторное использование делегата представления, и ошибка начала отображаться. Я отредактировал вопрос.   -  person suisied    schedule 16.09.2015


Ответы (1)


Подпрофессии для инженера имеют 4 значения в своем массиве, и из кода, которым вы с нами поделились, я вижу, что это единственная проблема, которая может вызвать эту ошибку.

Если UIPickerView попытается отобразить 4-ю строку во втором компоненте, он вызовет делегата (как вы написали). В этой реализации вы вызываете firstFieldArray[row]. В этот момент строка равна 3, но firstFieldArray имеет только 3 значения, поэтому максимальный индекс в этой точке равен 2.

Короче говоря, не создавайте titleLabel, если компонент равен 1, и в противном случае не создавайте titleLabel2, если компонент равен 0. В случаях, когда вы не уверены, что массив содержит количество значений, вы пытаетесь получить индекс , сделайте защитное кодирование:

// Check if the array holds the same or more values then 'row'
if array.count > row {
    return array[row]
}

ИЗМЕНИТЬ

Вот пример того, как вы можете улучшить свою реализацию делегата. Таким образом, ваш код не будет пытаться получить элемент из неправильного массива. Вы уже перезагружаете компоненты pickerView каждый раз, когда выбираете новый элемент из средства выбора, поэтому он должен снова вызывать DataSource & Delegates.

// UIPickerViewDataSource
func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int
    if component == 0 {
        return firstFieldArray.count
    } else {
        return secondFieldArray.count
    }
}

//UIPickerViewDelegate
func pickerView(pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusingView view: UIView?) -> UIView {
    let pickerLabel = UILabel()

    if component == 0 {
        // By placing it within the if-statement, this array won't be searched by index unnecassary.
        // So even if the second component would hold 4 or more items, it won't try to fetch 4th or higher index from this first array.
        let titleLabel = firstFieldArray[row]
        let myTitle = NSAttributedString(string: titleLabel, attributes: [NSFontAttributeName:UIFont(name: "Georgia", size: 15.0)!,NSForegroundColorAttributeName:UIColor.blackColor()])
        pickerLabel.attributedText = myTitle
    } else {
        let titlelabel2 = secondFieldArray[row]
        let myTitle = NSAttributedString(string: titlelabel2, attributes: [NSFontAttributeName:UIFont(name: "Georgia", size: 15.0)!,NSForegroundColorAttributeName:UIColor.blackColor()])
        pickerLabel.attributedText = myTitle
    }
    return pickerLabel
}
person Justin Hammenga    schedule 16.09.2015
comment
Я выровнял оба массива (3:3) в обоих компонентах, и все работает гладко. Спасибо, я понимаю, о чем вы говорите, но не могли бы вы подробнее (технически) рассказать о защитном кодировании, используя мой код выше. - person suisied; 16.09.2015
comment
if secondFieldArray.count › firstFieldArray.count { var error: NSError? print(обнаружена ошибка - (ошибка)) } в этой строке кода возникает ошибка - person suisied; 16.09.2015
comment
Я отредактировал свой ответ. Таким образом, если вы получаете строку для второго компонента, не используйте эту строку в массиве первого компонента и наоборот. - person Justin Hammenga; 16.09.2015