Передача данных между несколькими ViewController

xcode
ios
swift3

#1

Всем доброй ночи!)Начал изуать свифт, азы вроде осваиваю, но вот как в ООП сунулся так - это лес. На просторах инета много инфы, как передавать данные с (T)TextField в (L)Label, или c L в L. Но дело в том, что это простейшая инфа, и совершенно не раскрывает суть передачи данных, манипуляции с памятью с переходом, допустим через Segue, а самое главное не ясны возможные логиги, которые можно применить к той или иной ситуации. Мой вопрос:
Допустим есть у меня 3 VC’a. На 1VC 3 TextField и 1 кнопка. Вводим допустим 3 Интовых числа в каждый (T) и по нажатию должно переходить во второй VC поигрался с кодом, вот что вышло:

// 1 VC
     class ViewController: UIViewController {

    @IBOutlet weak var numOne: UITextField!
    @IBOutlet weak var numTwo: UITextField!
   
    
    @IBAction func pushNextButton(_ sender: Any) {
        
        if numOne.text! == ""
        {
            return
        }
        if numTwo.text! == ""
        {
            return
        }
        performSegue(withIdentifier: "nextOne", sender: self)
    }
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        
        let destinationController = segue.destination as! ViewController2
        
        destinationController.enterNumberOne = Int(numOne.text!) // здесь выдает ошибку
        destinationController.enterNumberTwo = Int(numTwo.text!) // здесь выдает ошибку 
            }
// Ошибка в 1VC
//    ( cannot assign value of type "Int" to type "UITextField!")  хотя тоже самое на втором VC не выдает :confused: 
}
// 2 VC
class ViewController2: UIViewController {
    
    var takeOneNum = 0
    var takeTwoNum = 0
    
    @IBOutlet weak var enterNumberOne: UITextField!
    @IBOutlet weak var enterNumberTwo: UITextField!

    @IBAction func nextTwo(_ sender: Any) {
        
        if enterNumberOne.text! == ""
        {
            return
        }
        if enterNumberTwo.text! == ""
        {
            return
        }
        performSegue(withIdentifier: "nextTwo", sender: self)
    }
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        let destanationController2 = segue.destination as! ViewController3
        destanationController2.answerOne = (enterNumberOne.text! as NSString).integerValue
        destanationController2.answerTwo = (enterNumberTwo.text! as NSString).integerValue
    }
    }

// 3VC
class ViewController3: UIViewController {
    @IBOutlet weak var itogOne: UILabel!
    @IBOutlet weak var itogTwo: UILabel!
    
    var answerOne = 0
    var answerTwo = 0
    
    override func viewDidLoad() {
        answerOne * takeOneNum
        answerTwo * takeTwoNum
        
        }
    
    @IBAction func closeButton(_ sender: Any) {
        dismiss(animated: true, completion: nil)
    }
  }

Не совсем понимаю логику. Вроде значения с 1 VC -> идут в переменные во 2VC, в 3 уже перемножаютя, ну или любое другое действие. Я не очень пойму как заставить сохраненные данные во втором VC сопрячь с данными во втором VC, толи во втором можно умножить, или это надо делать в 3? Собственно в этом и вопрос.

Итог: как перемножить 1 филд в 1 вью, с 1 филдом во втором вью, и второй филд в первом вью, со вторым филдом во втором вью? Извиняюсь за мой “французский”)

П.С хотелось бы получить краткий ясный ответ для НОВИЧКА в этом деле, с объяснением логики!) Можно прям закоментить в коде. Если еще и ссылочки есть, где объясняется подробно концепция работы с бордом и вью, или что-то подобное, то было бы найс просто. Надеюсь мы справимся!


#2

Вы не привязались к идентификатору сигвея. Вот пример из моего приложения. Это передача данных через сигвей между двумя контроллерами, но их может быть и больше. Создаем во втором контроллере переменную ncsColors и передаем в нее значение из массива первого контроллера. Важно прописать идентификатор сигвея в настройках самого сигвея. В вашем случае вы меняете ncsColors на, например, textLabel.text и т.д.

// MARK: - Navigation
    
    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "showDetailsSegue" {
            if let indexPath = self.tableView.indexPathForSelectedRow {
                let destinationVC = segue.destination as! DetailsTableViewController
                destinationVC.ncsName = self.favorites.favoritesList[(indexPath as NSIndexPath).row].name
            }
        }
    }

#3

Передавайте через делегат )


#4

Игнорируйте ответы выше, они не правильны

class ViewController: UIViewController {

	@IBOutlet weak var numOne: UITextField!
	@IBOutlet weak var numTwo: UITextField!

	@IBAction func pushNextButton(_ sender: Any) {
    	guard numOne.text! == "", numTwo.text! == "" else { return }
    	performSegue(withIdentifier: "nextOne", sender: nil)
		// зачем вы передаете в сендер селф?
	}
	
	override func viewDidLoad() {
    	super.viewDidLoad()
	}
	
	override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    	guard let destinationController = segue.destination as? ViewController2 else { return }
		guard let firstNum = Int(numOne.text), let secondNum = Int(numTwo.text) else { return }
    	destinationController.takeOneNum = firstNum
    	destinationController.takeTwoNum = secondNum
		// еще бы оно не выдавало ошибку, вы же присваиваете текстфилду инт. Читайте ошибки, которые вам IDE пишет.
    }

}

class ViewController2: UIViewController {

	var takeOneNum: Int = 0
	var takeTwoNum: Int = 0

	@IBOutlet weak var enterNumberOne: UITextField!
	@IBOutlet weak var enterNumberTwo: UITextField!

	@IBAction func nextTwo(_ sender: Any) {
        guard enterNumberOne.text! == "", enterNumberTwo.text! == "" else { return }
		performSegue(withIdentifier: "nextTwo", sender: nil)
	}


	override func viewDidLoad() {
  	  super.viewDidLoad()
	}
	

	override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
		guard let destinationController = segue.destination as? ViewController3 else { return }

		// а это что вы делаете? Зачем здесь NSString? 
    	//destanationController.answerOne = (enterNumberOne.text! as NSString).integerValue
    	//destanationController.answerTwo = (enterNumberTwo.text! as NSString).integerValue
		guard let first = Int(enterNumberOne.text), let second = Int(enterNumberTwo.text) else { return }
		destinationController.answerOne = first * takeOneNum
		destinationController.answerTwo = second * takeTwoNum
	}
}

class ViewController3: UIViewController {
	
	@IBOutlet weak var itogOne: UILabel!
	@IBOutlet weak var itogTwo: UILabel!

	var answerOne: Int = 0
	var answerTwo: Int = 0

	override func viewDidLoad() {
		// а этим вы что пытались сделать? Чему вы присваиваете значение умножения? Это вы так пытаетесь вызвать поле одного класса в другом?
    	//answerOne * takeOneNum
    	//answerTwo * takeTwoNum
		itogOne.text = answerOne.description
		itogTwo.text = answerTwo.description
    }

	@IBAction func closeButton(_ sender: Any) {
		// этот вью контроллер у вас модально отображается?
    	dismiss(animated: true, completion: nil)
	}
}

#5

Во время выполнения

IBOutlet-ы еще не созданы.


#6

Попробуйте зайти с другой стороны:

class NumManager {
    static let `default` = NumManager()
    
    var one = 0
    var two = 0
}

class ViewController: UIViewController {
    
    @IBOutlet weak var numOne: UITextField!
    @IBOutlet weak var numTwo: UITextField!
    
    @IBAction func pushNextButton(_ sender: Any) {
        guard let one = Int(numOne.text!), let two = Int(numTwo.text!) else { return }
        let manager = NumManager.default
        manager.one = one
        manager.two = two
        
        performSegue(withIdentifier: "nextOne", sender: nil)
    }
}

class ViewController2: UIViewController {
    
    @IBOutlet weak var enterNumberOne: UITextField!
    @IBOutlet weak var enterNumberTwo: UITextField!
    
    @IBAction func nextTwo(_ sender: Any) {
        guard let one = Int(enterNumberOne.text!), let two = Int(enterNumberTwo.text!) else { return }
        let manager = NumManager.default
        manager.one *= one
        manager.two *= two
        
        performSegue(withIdentifier: "nextTwo", sender: nil)
    }
}

class ViewController3: UIViewController {
    
    @IBOutlet weak var itogOne: UILabel!
    @IBOutlet weak var itogTwo: UILabel!
    
    override func viewDidLoad() {
        let manager = NumManager.default
        itogOne.text = manager.one.description
        itogTwo.text = manager.two.description
    }
}

#7

1 VC
“destanationController.answerOne = (enterNumberOne.text! as NSString).integerValue
destanationController.answerTwo = (enterNumberTwo.text! as NSString).integerValue”
//только так ошибку не выдает, переделать думал только так можно в Int значения строку.

2 VC
“performSegue(withIdentifier: “nextOne”, sender: nil)
зачем вы передаете в сендер селф?” // почему у меня возможная алогичность в коде, я описал в первом посте “П.С хотелось бы получить краткий ясный ответ для НОВИЧКА в этом деле, с объяснением логики!)”

3 VC
@IBAction func closeButton(_ sender: Any) {
// этот вью контроллер у вас модально отображается?
dismiss(animated: true, completion: nil)” //у меня все вью переходом Present Modally

" а этим вы что пытались сделать? Чему вы присваиваете значение умножения? Это вы так пытаетесь вызвать поле одного класса в другом?
answerOne * takeOneNum
answerTwo * takeTwoNum"
//тоже описал выше “Я не очень пойму как заставить сохраненные данные во втором VC сопрячь с данными во втором VC, толи во втором можно умножить, или это надо делать в 3?”

  • теперь вроде логика ясна, но при запуске приложения выдается ошибка в файле AppDelegate:
    “Thread 1: signal SIGABRT” - а в файлах появился знак “?” :

    иными словами оно вообще не запускается.
    Подумал может xCodе глючит или я настроил в StoryBoard что-то не то, собрал похожее приложение с вашим кодом, ошибок не выдавало, запустилось, но при внесении данных в TextField на след экран, по нажатию на кнопку не переходит во второй вью. А если не вносить переходит.

#8

Вы должны четко понимать что вы делаете, поэтому я задал все эти вопросы. Не для себя, а для вас. Если не понимаете что вы делаете - гуглите, ищите информацию в документации, нельзя тупо копировать код.
Передавать self в sender не нужно потому, что через sender передается информация в

override func prepare(for segue: UIStoryboardSegue, sender: Any?) 

а вам ничего передавать не нужно и уж тем более не нужно передавать self (а это ссылка на текущий вью контроллер в данном случае).

Я писал код на сайте, так что он не тестировался. Возможно я что-то не учел. Ошибка у вас должна быть описана в консоли.


#9

Что к чему относится я грубо, но понимаю. Собственно четкого понимания не может быть у меня, я бы тогда сюда не пришел). Вот отшибка, котороую выдает:


Не понимаю, почему он выводит название enterNumber1, когда филд называется enterNumberOne? Где можно посмотреть откуда в консоль вывелось “enterNumber1”?


#10

Вы, скорее всего, создали оутлет с названием enterNumber1, а затем переименовали его. В сториборде щелкните на нем пкм, и удалите строку с восклицательным знаком.