Index out of range


#1

Всем привет! Бьюсь второй день на индексом за границей массива=(
Это мой первый проект
Имеется 1 Navigation, 2 View и 1 TabelView
В 1 View юзер вносит определенные данный(скорость ветра и температуру), далее переходит в TabelView, где вносит величины площадей, потом нажимает кнопку расчет и переходит в 2 view, в котором отображается расчет в text view

для расчета берутся данные введенные на 1 и 2 шаге. У меня есть 3 класса, по 1 на каждый контроллер, в 3 классе произвожу расчет, для этого по средствам prepareForSegue передаю данные из 1 и 2 контроллера в 3й.

xcode не ругается на код и все вроди бы логично, но когда тестирую в симуляторе, то вылазит ошибка=(

ссылка на проект

Помогите решить проблемку


#2

Можно ошибку и фрагмент кода, в которой она возникает. (В проекте то никто копаться не будет)


#3

let a1 = 1 + 0.0009 * pow(Double(wind[0])!, -1.12) * pow(inletChamberArea, 0.315) * Double(temp[0])!
print (a1) //fatal error: Index out of range

Вот тут ошибка

Фрагмент кода

var temp = String
var wind = String
var build = (title: String, area: String, areaShelter: String)

// Площадь сооружений
// Приемная камера
var inletChamberArea: Double = 0.00
var inletChamberAreaShelter: Double = 0.00

// Решетка
var gridArea: Double = 0.00
var gridAreaShelter: Double = 0.00

// Песколовка
var sandTrapArea: Double = 0.00
var sandTrapAreaShelter: Double = 0.00

// Первичный отстойник
var primarySettlerTrapArea: Double = 0.00
var primarySettlerTrapAreaShelter: Double = 0.00

// Аэротэнк
var aerotankArea: Double = 0.00
var aerotankAreaShelter: Double = 0.00

// Вторичный отстойник
var secondarySettlerArea: Double = 0.00
var secondarySettlerAreaShelter: Double = 0.00

// Иловый резервуар
var silkTankArea: Double = 0.00
var silkTankAreaShelter: Double = 0.00

// Уплотнитель сырого осадка
var sealingRawSludgeArea: Double = 0.00
var sealingRawSludgeAreaShelter: Double = 0.00

// Уплотнитель сброженного осадка
var sealDigestedSludgeArea: Double = 0.00
var sealDigestedSludgeAreaShelter: Double = 0.00

// Песковая площадка
var sandPlaygroundArea: Double = 0.00
var sandPlaygroundAreaShelter: Double = 0.00

// Иловая площадка
var siltPlaygroundArea: Double = 0.00
var siltPlaygroundAreaShelter: Double = 0.00

// Множитель при ветре меньше 3 (2.7*10^-5)
let factorLess3 = 0.000027

// Множитель при ветре больше 3 (0.9*10^-5)
let factorGreater3 = 0.000009

override func viewDidLoad() {
    super.viewDidLoad()
    
    // Извлекаем площади из массива
    for item in build {
        switch item.title {
        case "Приемная камера":
            inletChamberArea = Double(item.area)!
            inletChamberAreaShelter = Double(item.areaShelter)!
        case "Решетка":
            gridArea = Double(item.area)!
            gridAreaShelter = Double(item.areaShelter)!
        case "Песколовка":
            sandTrapArea = Double(item.area)!
            sandTrapAreaShelter = Double(item.areaShelter)!
        case "Первичный отстойник":
            primarySettlerTrapArea = Double(item.area)!
            primarySettlerTrapAreaShelter = Double(item.areaShelter)!
        case "Аэротэнк":
            aerotankArea = Double(item.area)!
            aerotankAreaShelter = Double(item.areaShelter)!
        case "Вторичный отстойник":
            secondarySettlerArea = Double(item.area)!
            secondarySettlerAreaShelter = Double(item.areaShelter)!
        case "Иловый резервуар":
            silkTankArea = Double(item.area)!
            silkTankAreaShelter = Double(item.areaShelter)!
        case "Уплотнитель сырого осадка":
            sealingRawSludgeArea = Double(item.area)!
            sealingRawSludgeAreaShelter = Double(item.areaShelter)!
        case "Уплотнитель сброженного осадка":
            sealDigestedSludgeArea = Double(item.area)!
            sealDigestedSludgeAreaShelter = Double(item.areaShelter)!
        case "Песковая площадка":
            sandPlaygroundArea = Double(item.area)!
            sandPlaygroundAreaShelter = Double(item.areaShelter)!
        case "Иловая площадка":
            siltPlaygroundArea = Double(item.area)!
            siltPlaygroundAreaShelter = Double(item.areaShelter)!
        default:
            print("No data")
        }
    }
    
    let a1 = 1 + 0.0009 * pow(Double(wind[0])!, -1.12) * pow(inletChamberArea, 0.315) * Double(temp[0])!
    print (a1)
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "buildToCalcSegue" {
        let buildVC = segue.destination as! BuildingsTableViewController
        buildVC.buildings = build
    }
    
    if segue.identifier == "varsToCalcSegue" {
        let varsVC = segue.destination as! VarsViewController
        temp.append(varsVC.temp1TextField.text!)
        
        wind.append(varsVC.windSpeed1TextField.text!)
    }
}

#4

Могу точно сказать, что в этой строке
let a1 = 1 + 0.0009 * pow(Double(wind[0])!, -1.12) * pow(inletChamberArea, 0.315) * Double(temp[0])!

у вас массивы wind и temp пустые, поэтому и index out of range.

вы их до момента инициализации текущего контроллера не заполнили
(запустил ваш проект и проверил)

ПС: отловить такие ошибки прекрасно помогают breakpoint’ы

и проверьте метод prepare в этом контроллере. у вас ошибка в понимании его работы.


#5

Это я увидел, но не пойму почему, разве

не суть метода передавать значение переменных из одного View в другой? если нет, то как же мне передать значения из одного View в другой? Во всем мангалах что я находил для этого используется как раз этот метод…


#6

Суть верна.
Для заполнения массивов temp и wind вы используете метод prepare, правильно ?

if segue.identifier == "varsToCalcSegue" {
    let varsVC = segue.destination as! VarsViewController
    temp.append(varsVC.temp1TextField.text!)
    wind.append(varsVC.windSpeed1TextField.text!)
}

Вы тут это делаете, да ?
А вы проверяли, вызывается ли этот метод ? И в том ли контроллере это используется ?

Да и самая грубая ошибка:
segue.destination - это контроллер в который осуществляется переход.
на момент вызова prepare этот контроллер не определен.
а вы пытаетесь у него получить значения, которых еще нет.


#7

Да, именно[quote=“manindaniil, post:6, topic:2893”]
А вы проверяли, вызывается ли этот метод ?
[/quote]

Не проверял, я же говорю, первый раз пишу программу, многого не знаю, поэтому тут и спрашиваю=)[quote=“manindaniil, post:6, topic:2893”]
Да и самая грубая ошибка:segue.destination - это контроллер в который осуществляется переход.на момент вызова prepare этот контроллер не определен.а вы пытаетесь у него получить значения, которых еще нет.
[/quote]

Правильно ли я понял? этот метод нужно перенести в varsViewController?

Я предполагал что этой строчкой

я обозначаю что VarsViewController это у меня переменная varsVC в CalculationViewController, а так как vars загружается раньше calculation, то он уже известен, а значит и сигвеи его тоже, видимо я что-то не дополнял… Мне сложновато перейти с C#, там было проще передавать значения переменных…


#8

Метод prepare вызывается в тот момент, когда вы осуществляете переход из контроллера А в контроллер Б и хотите передать какие-то параметры из А в Б.
То есть использовать вы его должны условно так

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
            if segue.identifier == "Идентификатор перехода из А в Б" {
               let контроллерБ = segue.destination as! КонтроллерБ.
               // тут вы можете заполнять параметры контроллера Б и выполнять какие нибудь расчеты. Например
              контроллерБ.title = self.title
              // Заголовок контроллерБ будет такой же как и на текущем контроллере
          }
} 

Как то так.
Я может быть вас тоже не совсем пойму в логике вашего приложения. Но я вижу что вы, находясь на CalculationViewController хотите с помощью метода prepare получить параметры из VarsViewController, но у вас нет такого перехода и идентификаторы, значит метод prepare не будет выполнен. prepare служит только для “движения” вперед ) С помощью него вы не можете получить параметры из предыдущих контроллеров. Для этого лучше использовать делегаты, рекомендую вам очень хорошо с ними разобраться ибо это то, что вы будете использовать чаще всего, так как передача параметров она повсюду )


#9

Спасибо Вам за совет, про делегаты посмотрел видео, вроде бы все понятно, но не разобрался в одном моменте, в видео Иван задает делегирование через все тот же prepare, не могу понять как же в моем случае его задать? Так как prepare уже никак не получиться, так как в 3й контроллер нет прямого перехода из 1ого. Пытался в View did load писать так

let vc = storyboard?.instantiateWith(identifiere: “VarsVC”) as! VarsViewController
vc.delegate = self //могут быть ошибка, не копипаст, пишу по памяти

Я инициализируются контроллер и делаю его делегатом

В контроллере из которого нужно передать данные я прописал протокол, в котором прописал метод, возвращающий массив из нужных мне элементов.

Правильно я делаю?