2015-02-04 6 views
11

У меня проблемы с моим UITableViewCells. Я подключил свой UITableView к API для заполнения моих ячеек.Push segue от UITableViewCell до ViewController в Swift

Затем я создал функцию, которая захватывает indexPath.row, чтобы определить, какой JSON-объект внутри массива должен быть отправлен на RestaurantViewController.

Link to my Xcode Project for easier debugging and problem-solving

Вот как мой маленький фрагмент кода выглядит для настройки «строки щелчки» глобальной переменной.

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { 
    i = indexPath.row 
} 

И вот моя prepareForSegue() функция, которая должна подключить мой нажимной SEGUE к RestaurantViewController.

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) { 
    if segue.identifier == "toRestaurant"{ 
    let navigationController = segue.destinationViewController as UINavigationController 
    let vc = navigationController.topViewController as RestaurantViewController 
    vc.data = currentResponse[i] as NSArray 
} 
} 

А вот как я настроил свой SEGUE от UITableViewCell

Вот мой результат, я попытался щелкнуть каждый из этих клеток, но не будет оттеснена другой viewController ... Я также не получаю сообщение об ошибке. Что здесь не так?

Пробовал решения, которые не будут работать

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) { 
     if segue.identifier == "toRestaurant"{ 
      let vc = segue.destinationViewController as RestaurantViewController 
      //let vc = navigationController.topViewController as RestaurantViewController 
      vc.data = currentResponse[i] as NSArray 
     } 
    } 
+0

Ошибка не исходит от строки: пусть navigationController = segue.destinationViewController как UINavigationController? Я думаю, что destinationController не является навигационным контроллером, а сам uiviewcontroller. –

+0

@ DánielNagy Я прокомментировал '' let vc = navigationController.topViewController как RestaurantViewController'' и отредактировал строку выше, чтобы иметь «RestaurantViewController». Скомпилированы и запущены, нет ошибок, просто нет ответа от нажатия на ячейки. – Jack

+0

Я только что проверил, что push segue устарел, я не уверен, но что, если вы измените это на Show (например, Push)? –

ответ

20

Проблема заключается в том, что вы правильно не обрабатывает данные. Если вы заглянете в свой массив , вы увидите, что он содержит NS-словари, но в вашем prepareForSegue вы пытаетесь применить NSDictionary к NSArray, что приведет к сбою приложения.

Изменение data переменной в RestaurantViewController к NSDictionary и изменить prepareForSegue передать ÄÂ NSDictionary

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) { 
    if let cell = sender as? UITableViewCell { 
     let i = redditListTableView.indexPathForCell(cell)!.row 
     if segue.identifier == "toRestaurant" { 
      let vc = segue.destinationViewController as RestaurantViewController 
      vc.data = currentResponse[i] as NSDictionary 
     } 
    } 
} 
+0

Я получаю сообщение об ошибке в строке 54: '' self.tableData = results as NSDictionary! ''. Ошибка: '' 'NSDictionary' не конвертируется в 'NSArray''' – Jack

+0

, в котором viewcontroller? – ergoon

+0

'' AutomaticCitySelectionViewController' – Jack

1

Попробуйте создать клетки, как это в вашем cellForRow метод:

let cell: UITableViewCell = tableView.dequeueReusableCellWithIdentifier("MyTestCell", forIndexPath: indexPath) 
+0

Теперь Я получил сообщение об ошибке: «Завершить приложение из-за неотображаемого исключения» NSInternalInconsistencyException », причина:« не удалось удалить ячейку с идентификатором MyTestCell - должен зарегистрировать ниб или класс для идентификатора или подключить прототип ячейки в раскадровке » – Jack

+0

Клетка, с которой вы связали свой segue с IB, должна иметь идентификатор повторного использования, установленный как «MyTestCell» – Starscream

+0

Добавил «MyTestCell» к идентификатору TableViewCell и получил мою консоль, написанную '' (lldb) '' в зеленом тексте и раскрыл нить. Он говорит: «EXC_REAKPOINT'' – Jack

2

Я заметил, что в вашем скриншоте вашего раскадровки, segue соединяет первую прототипную ячейку до RestaurantViewController. Эта прототипная ячейка выглядит так: «Основной» стиль ячейки с аксессуаром индикатора раскрытия справа. Но посмотрите на скриншот вашего приложения. Таблица заполняется ячейками, которые, как представляется, являются типом «Subtitle» для ячейки без аксессуара индикатора раскрытия справа.

Причина, по которой ваш segue никогда не срабатывает, независимо от того, что вы делаете, заключается в том, что segue настроен только на работу с определенной ячейкой прототипа, но эта ячейка прототипа никогда не используется, когда вы заполняете таблицу. Что бы вы ни делали в tableView:cellForRowAtIndexPath:, вы не используете ячейку прототипа, которую хотите.

@Starscream имеет правильную идею, деактивирующую правую ячейку с правильным идентификатором и сопоставляя ее с идентификатором ячейки прототипа в Interface Builder. Сбой, который вы получаете даже после этого, может быть из-за предыдущей проблемы, упомянутой в комментариях выше. Ваш segue в раскадровке явно указывает на UITableViewController. Ваш код в prepareForSegue:sender: должен быть let vc = segue.destinationViewController as RestaurantViewController, пока RestaurantViewController является подклассом UITableViewController. Вы потерпите крах, если попытаетесь использовать его как UINavigationController. Также убедитесь, что класс для адресата UITableViewController в раскадровке указан как RestaurantController в панели «Проверка идентификатора». Вы столкнетесь, если ваша программа компилирует, думая, что раскадровка просто содержит общий номер UITableViewController.

Возвращаясь к исходной проблеме больше, я не знаю, как вы внедрили tableView:cellForRowAtIndexPath:, что может иметь решающее значение. Может быть, это не так просто. Возможно, вы планируете обрабатывать многие прототипные ячейки или создавать пользовательские ячейки во время выполнения. В этом случае один из способов сделать это простым для вас - программно выполнить сеанс, когда пользователь нажимает на ячейку. Вместо использования определенной ячейки прототипа сделайте segue соединение, исходящее из «Restauranger nära mig» UITableViewController, идущее на RestaurantViewController. (Подключитесь в Interface Builder, перетаскивая элемент управления с помощью значка контроллера таблиц в верхней части первой, в тело второго). Вы должны дать этому segue идентификатор в панели Attributes Inspector, чтобы сделать это полезным. Скажем, это "toRestaurant". Затем в конце вашего метода tableView:didSelectRowAtIndexPath: поместите эту строку кода: self.performSegueWithIdentifier("toRestaurant", sender: self). Теперь, независимо от того, какая ячейка выбрана в таблице, этот отступ всегда будет срабатывать для вас.

3

Dropbox link to stack3 directory

  1. Я трудно понять, почему ваша программа сильно отличается от стандартной структуры Tableview 2 уровня. Поэтому я закодировал короткий пример, к которому вы можете получить доступ по этой ссылке. Я также включил исходный код ниже.

  2. Программа имитирует то, что у вас есть (насколько я понял). Контроллер таблицы 1 отбирается в Table Controller 2 из ячейки tableview. У меня не было проблем с segue-ing. Обратите внимание, что мне не нужно и не нужно увеличивать Историю, чтобы инициировать сеанс.

  3. Я включил оба контроллера в навигационных контроллерах. Мой опыт в том, что он экономит много усилий для настройки навигации.

  4. В качестве альтернативы, я мог бы перетащить управление из первого символа TableViewController поверх экрана во второй контроллер и настроить сеанс.

  5. Я использовал глобальную переменную (selectedRow), хотя это не рекомендуется. Но вы так же легко можете использовать prepareForSegue для установки переменной в RestaurantTableViewController (я покажу пример)

    1. Наконец, я рекомендую проверить Инспектор подключений (для ячейки таблицы таблицы в первый контроллер), чтобы подтвердить, что во втором контроллере есть сегмент. Если вы управляете перетаскиванием должным образом, должно быть подтверждено приглашение, а также запись в инспекторе соединений.

К сожалению, я просто не могу получить код правильно FORMATTER

import UIKit 

var selectedRow = -1 

class TableViewController: UITableViewController { 

var firstArray = ["Item1","Item2","Item3","Item4"] 

override func viewDidLoad() { 

super.viewDidLoad() 

} 

override func didReceiveMemoryWarning() { 

super.didReceiveMemoryWarning() 

} 

// MARK: - Table view data source 

override func numberOfSectionsInTableView(tableView: UITableView) -> Int { 

return 1 
} 

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 

return firstArray.count 

} 


let nameOfCell = "RestaurantCell" 

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

let cell = tableView.dequeueReusableCellWithIdentifier(nameOfCell, forIndexPath: indexPath) as UITableViewCell 

cell.textLabel!.text = firstArray[indexPath.row] 

return cell 

} 

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { 

selectedRow = indexPath.row 

} 

// MARK: - Navigation 

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { 

let vc = segue.destinationViewController as RestaurantTableViewController 

// can write to variables in RestaurantTableViewController if required 

vc.someVariable = selectedRow 

} 


} 


import UIKit 

class RestaurantTableViewController: UITableViewController { 

var secondArray = ["Item 2.1", "Item 2.2", "Item 2.3", "Item 2.4"] 

var someVariable = -1 

override func viewDidLoad() { 

super.viewDidLoad() 

} 

override func didReceiveMemoryWarning() { 

super.didReceiveMemoryWarning() 

} 

// MARK: - Table view data source 

override func numberOfSectionsInTableView(tableView: UITableView) -> Int { 

return 1 

} 

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 

return secondArray.count 

} 

let nameOfCell = "RestaurantCell" 

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

let cell = tableView.dequeueReusableCellWithIdentifier(nameOfCell, forIndexPath: indexPath) as UITableViewCell 

cell.textLabel!.text = secondArray[indexPath.row] 

if indexPath.row == selectedRow { 

cell.textLabel!.text = cell.textLabel!.text! + " SELECTED" 

} 

return cell 

} 

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { 

selectedRow = indexPath.row 

} 

} 
+0

Так я тоже создаю свой проект. Только я смущен почему ваш 2-й контроллер табличного представления подталкивается по-разному, а не по умолчанию, и почему не появляется обратная кнопка. – PostCodeism

1

Im выходя на прихоть здесь, так как я просто попасть в стрижа прямо сейчас, но так, как я делаю это в моем prepareForSegue() это что-то вроде этого:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) { 
    if segue.identifier == "toRestaurant"{ 
     let navigationController = segue.destinationViewController as UINavigationController 
     let vc = navigationController.topViewController as RestaurantViewController 
     //notice I changed [i] to [index!.row] 
     vc.data = currentResponse[index!.row] as NSArray 
    } 
    } 

что мне кажется, что вы вызываете переменную я, который вроде как частный variabl e внутри метода вашего класса.Вы можете сделать что-то вроде @Syed Тарик сделал с переменной selectRow и установить его над вашим class SomeController: UIViewController /*, maybe some more here? */ {, а затем подписать переменную внутри метода

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { 

    selectedRow = indexPath.row 

} 

, как описано выше, но обе стороны должны работать достаточно хорошо.

+0

Я попробовал '' prepareForSegue() '', но не повезло, и этот метод 'tableView'' также вместе с eachother. Я просто получил ошибку '' 0x102883662: nopw% cs: (% rax,% rax) '' при нажатии строки таблицы. – Jack

+0

Возможно, это может быть ваш '' 'currentResponse'''? Я не знаю, что это такое. У вас что-то зарегистрировано? – KyleMassacre

+0

Не думайте так, это пустой '' NSArray'', который заполняется функцией. – Jack

4

Следующие действия должны устранить вашу проблему. Если нет, сообщите мне.

  1. Удалите свою реализацию tableView(tableView, didSelectRowAtIndexPath:).

  2. Сделать data на RestaurantViewController имеют тип NSDictionary!

  3. Определить выбранную строку в prepareForSegue:

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) { 
        if let cell = sender as? UITableViewCell { 
         let i = tableView.indexPathForCell(cell)!.row 
         if segue.identifier == "toRestaurant" { 
          let vc = segue.destinationViewController as RestaurantViewController 
          vc.data = currentResponse[i] as NSDictionary 
         } 
        } 
    } 
    
+0

Мои консольные выходы '' (lldb) '' и * Thread 1 * открывается ('' swift_dynamicCastObjCClassUnconditional''). – Jack

+0

Ссылка на мой [проект Xcode] (https://mega.co.nz/#!t89CiAKD!qOemhVZ6yCNDfsc-H43Yk4vady7yIqUx3V9d-4NrglQ) – Jack

+0

Получение ошибки звучит как 90% пути. Если вы замените самые внутренние строки на 'println (segue.destinationViewController!)', Что вы получаете как вывод? –

0

Я была такая же проблема, и я нашел решение быть:

performSegueWithIdentifier ("toViewDetails ", отправитель: самостоятельно)

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { 
    var cellnumber = procMgr.processos[indexPath.row].numero 
    println("You selected cell #\(indexPath.row)") 
    println(cellnumber) 
    performSegueWithIdentifier("toViewDetails", sender: self) 
} 

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { 
    if segue.identifier == "toViewDetails" { 
     let DestViewController : ViewDetails = segue.destinationViewController as! ViewDetails 
    } 
} 
+0

Я думаю, сначала вызовите метод prepareForSegue, затем сделалSelectRowAtIndexPath ... –

0

Возможно, вам понадобится получить выбранный индекс ячейки UItableview. Ниже код использовал выделенный индекс ячейки (UItableview.indexPathForSelectedRow), чтобы получить правильный элемент массива.

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) { 
    if segue.identifier == "seguaVisitCardDetial" { 
     let viewController = segue.destinationViewController as! VCVisitCardDetial 
     viewController.dataThisCard = self.listOfVisitCards[(tblCardList.indexPathForSelectedRow?.row)!] 
    } 
} 
Смежные вопросы