2016-07-03 2 views
0

У меня есть два ViewControllers. У одного есть TableView и кнопка Add, которая ведет нас ко второму ViewController, у которого есть текстовое поле и кнопка действия. Предполагается, что пользователь должен вставить текст в таблицу на втором экране с текстовым полем.Ошибка при переключении с одного контроллера вида на другой

Я сделал отдельные быстрые файлы для двух контроллеров представления. Для второго представления я импортирую класс своего первого представления. Однако, когда я пытаюсь нажать кнопку добавления, чтобы перейти ко второму контроллеру представления, я получаю дополнительную ошибку обертывания. Это ошибка, которую я получаю: фатальная ошибка: unexpectedly found nil while unwrapping an Optional value. И в режиме отладки, он выделяет следующую строку кода:

tableview.setEditing(true, animated: true) 

код для моего первого контроллера представления, который имеет TableView:

class MainScreen : UIViewController, UITableViewDataSource, UITableViewDelegate { 


var items = ["Apple", "Fish", "Dates", "Cereal", "Ice cream", "Lamb", "Potatoes", "Chicken", "Bread"] 


@IBOutlet weak var tableview: UITableView! 

override func viewDidLoad() { 
    super.viewDidLoad() 

    // Do any additional setup after loading the view, typically from a nib. 
    tableview.setEditing(true, animated: true) 

} 

override func didReceiveMemoryWarning() { 
    super.didReceiveMemoryWarning() 
    // Dispose of any resources that can be recreated. 
} 
    func numberOfSectionsInTableView(tableView: UITableView) -> Int { 
    return 1 
} 

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 
    return items.count 
} 

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { 

    let iD = "normal" 
    let cell = tableView.dequeueReusableCellWithIdentifier(iD, forIndexPath: indexPath) 
    cell.textLabel?.text = items[indexPath.row] 
    return cell 
} 


func tableView(tableView: UITableView, editingStyleForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCellEditingStyle { 
    return UITableViewCellEditingStyle.None 
} 



func tableView(tableView: UITableView, moveRowAtIndexPath sourceIndexPath: NSIndexPath, toIndexPath destinationIndexPath: NSIndexPath) { 
    if (sourceIndexPath.row != destinationIndexPath.row){ 
     let temp = items[sourceIndexPath.row] 
     items.removeAtIndex(sourceIndexPath.row) 
     items.insert(temp, atIndex: destinationIndexPath.row) 

    } 
    tableView.reloadData() 
} 

}

Код для моего второго контроллера представления который имеет текстовое поле и кнопку для ввода текста в мой массив (позиции)

class TextScreen : MainScreen { 


    @IBOutlet weak var keyboard: UITextField! 

    @IBAction func insert(sender: AnyObject) { 

     items.append(keyboard.text!) 

    } 


    override func viewDidLoad() { 
     super.viewDidLoad() 
     // Do any additional setup after loading the view, typically from a nib. 
    } 

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

}

Я не знаю, что я делаю неправильно. Я также добавил скриншот.

+0

Вам необходимо реализовать требуемые функции UITableViewDataSource и UITableViewDelegate – Roee84

+0

@ Roee84 My TableView уже подключен к DataSource и Delegate. Я сделал это в Раскадровке. Что ты хочешь этим сказать? Не могли бы вы объяснить больше? Я также установил ячейки и все, но код здесь не показан. –

+1

Похоже, что ваша версия 'tableview' -' nil'. Вы связали его с раскадрой? – vacawama

ответ

0

То, что вы пытаетесь достичь, должно обрабатываться с помощью метода делегата вместо подкласса MainScreen.

Протокол предписывает структуру классу. Если в протоколе определена функция. Класс, реализующий протокол, должен иметь эту функцию. Вот почему, если вы ссылаетесь на делегат от MainScreen, например delegate = self, класс, содержащий делегат, может запускать любую функцию, указанную в протоколе. Это передает данные в функции из TextScreen в функцию, реализованную в MainScreen

Вы хотите добавить строку в массив, вам нужна функция, которая отправляет строку (или обрабатывает ее). Это этикет также включает отправителя.

Создание протокола:

protocol TextScreenDelegate { 
    func sendTextToDelegate(sender: TextScreen, text: String) 
} 

Теперь вы должны разместить делегата на ваш взгляд TextScreen как свойство этого класса:

Этот делегат будет создать связь между классом, который хочет использовать данных и класса, содержащего данные. Когда метод из протокола в TextScreen выполняются (delegate.sendTextToDelegate()) он будет идти к любому виду, который ссылается его, например, в prepareforSegue В начале (см ниже)

var delegate : TextScreenDelegate? 

Теперь В начале соответствовать вашему недавно созданный протокол, добавьте его следующим образом:

Теперь нам нужно убедиться, что MainScreen соответствует этому протоколу. Также, если вы используете UITableView и т. Д., Вам нужно добавить свой собственный протокол. Помните, что TableView не будет работать, если вы не используете реализации протокола, и наш TextScreen не будет!

class MainScreen : UIViewController, UITableViewDataSource, UITableViewDelegate, TextScreenDelegate 

Он скажет, что это не соответствует, потому что вам не хватает метода делегата, созданного выше. Внесите это и сделайте то, что вы хотите сделать:

Теперь, когда вы добавили протокол к MainScreen, вы должны создать функцию, которую вы определили сами в протоколе. Каждая функция там должно быть добавлено в начало В так:

func sendTextToDelegate(sender : TextScreen, text : String) { 
    self.items.append(text) 
} 

Чтобы быть в состоянии позволить TextView знать, что вы хотите распространять данные на этот делегат вам нужно ссылаться на него. У вашего prepareForSegue выглядит примерно так:

Об этом мы говорили выше, создавая связь между TextScreen и MainScreen. В начале (который реализует TextScreenDelegate протокола) используется для связи (см vc.delegate = сами)

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { 
    if segue.identifier == "YourIdentifier" { 
     if let vc = segue.destinationViewController as? TextScreen { 
      vc.delegate = self 
     } 
    } 
} 

Al, что осталось, чтобы вызвать функции в ваших TextScreen сейчас Когда вы выполните свое действие, сообщите об этом делегату! Теперь в вашем TextScreen вы можете просто вызвать методы делегата. Использование кода:

@IBAction func insert(sender: AnyObject) { 

    // Always check if exists! 
    guard let text = self.keyboard.text 
     else { 
      print("error - no text in keyboard") 
      return 
    } 
    delegate?.sendTextToDelegate(sender: self, text: text) 
} 

Убедитесь, что TextScreen является UIView снова и не подкласс В начале:

TextScreen : UIView 

Это мнение по себе;)

Это кажется быть более чистым подходом к обработке того, что вы хотели бы сделать.

- EDIT 2 -

Существует грязный способ проверить методы делегата. Создайте массив в AppDelegate и добавьте к нему.

в AppDelegate.swift

var items : [String] = ["Apple", "Fish", "Dates", "Cereal", "Ice cream", "Lamb", "Potatoes", "Chicken", "Bread"] 

Теперь в вашем MainScreen.swift

изменить ваши детали к:

var items : [String] = [] 

и в вашем viewDidLoad()

let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate 
self.items = appDelegate.items 
self.tableView.reloadData() 

и в y ou TextScreen.swift

let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate 
appDelegate.items.append('your item') 

Это сохранит их в массиве в AppDelegate. Это, однако, рекомендуется только для целей тестирования вашего TableView. Правильный способ - использовать Core Data. Который имеет множество примеров на google.

+0

большое спасибо! Однако это может показаться глупым, но я не прочитал протоколы, поэтому я не понимаю большую часть кода, который вы написали. Можете ли вы пройти меня? Кроме того, если я правильно понимаю, я создаю протокол в файле MainScreen? Пожалуйста помоги. Кроме того, TextScreen должен импортировать из MainScreen, правильно? не UIViewController? –

+0

и я не понимаю работы и причины подготовкиForSegue в вашем коде. не могли бы вы объяснить? –

+0

Я обновил свой ответ, не могли бы вы перепроверить, и если вы этого не поймете, дайте мне знать! Может быть, хотя пилюлю проглотить через 1 неделю;) – Emptyless

Смежные вопросы