2015-11-11 2 views
3

У меня есть два файла: MyTableViewController и myViewController. Я установил UIImageView на TableCell в MyTableVIewController. myViewController ничего не содержит. И я создал массив с именем ImageArray, который содержит массив изображений.Передача данных между контроллерами View в Swift (от TableView до DetailViewController)

Что я делаю здесь, когда я нажимаю изображение на TableCell в myTableViewController, я хочу, чтобы щелкнуло изображение в myViewController. И некоторое описание об щелкном изображении рядом с изображением тоже. Я хочу использовать myViewController для получения подробной информацией о выбранном изображении.

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { 
    let cell = self.tableView.dequeueReusableCellWithIdentifier("Cell") as! UITableViewCell 
    var ImageView = cell.viewWithTag(1) as! UIImageView 
    ImageView.image = UIImage(named: ImageArray[indexPath.row]) 
    ImageView.contentMode = .ScaleAspectFit 

    var TextView = cell.viewWithTag(2) as! UILabel 
    TextView.text = ImageArray[indexPath.row] 
    return cell 
} 

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { 
    performSegueWithIdentifier("next", sender: indexPath) 
} 

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { 
    if (segue.identifier == "next") { 
     let destination = segue.destinationViewController as! myViewController 
    } 
} 

Я не знаю, что делать, чтобы это произошло. Я очень признателен, если вы поможете мне разобраться! Благодаря!

ответ

4

Прежде всего, я предполагаю, что ваш MyTableViewController класс соответствует как UITableViewDataSource и UITableViewDelegate протоколов и что вы настроили ваш класс MyTableViewController быть делегатом в коде или с помощью раскадровки.

С учетом этого существует несколько способов достижения результата, который вы ищете. Вы можете объявить ImageArray в самостоятельный класс и назовите его внутри MyTableViewController класса, индекс их на Tableview используя методы делегата Tableview, и, наконец, с помощью метода prepareForSegue нажать изображения на ваш myViewController. Или вы можете просто объявить и инициализировать ImageArray в верхней части MyTableViewController класса, как показано ниже:

var ImageArray = [("Moscow Russia.jpg", "Europe"), 
    ("London England.jpg", "Europe")] 

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

Затем мы указываем, сколько строк в разделе нам нужно ImageArray, чтобы занять на нашем столеView (т.в основном считать наши ImageArray в нашу TableView) с ниже требуемого метода:

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

Далее, вы хотите, чтобы представить свой ImageArray в каждой строке ячейки, используя Tableview: cellForRowAtIndexPath: метод.

Side Примечание на вашем TableCell: Надеюсь, ваш TableCell является подклассами UITableViewCell, и вы уже объявили и соединили две IBOutlets, скажем, ImageView и TextLabel соответственно. Кроме того, убедитесь, ваш TableCell правильно связан с вашим прототипом ячейки в раскадровке под Удостоверение инспектора) Ваш класс TableCell должен выглядеть, как показано ниже:

import UIKit 
class CustomTableViewCell: UITableViewCell { 
@IBOutlet weak var imageView: UIImageView! 
@IBOutlet weak var textLabel: UILabel! 
} 

Теперь обратно в MyTableVIewController класса. Из вашего кода я вижу, что вы выбрали строку «let cell = ...» как «UITableViewCell». Вместо этого вы должны использовать его как «TableCell», так как вы подклассифицируете его. Реализовать Tableview: cellForRowAtIndexPath: метод следующим образом:

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell 
{   
    let cell = self.tableView.dequeueReusableCellWithIdentifier("Cell") as! TableCell 

//Note that I'm using tuples here. Pretty cool huh. Got to love Swift! 
    let (imageName, textNameToGoWithImage) = ImageArray[indexPath.row] 

    cell.textLabel.text = textNameToGoWithImage 
    cell.imageView.image = UIImage(named: imageName) 
    cell.imageView.contentMode = .ScaleAspectFit 

// You could have also used 'if let' in optional binding to safely unwrap your image if you want like below. 
    // if let image = UIImage(named: imageName){ 
    //  cell.imageView?.image = image 
    //   cell.imageView.contentMode = .ScaleAspectFit 
    //  } 

    return cell 
} 

Похоже, вы немного запутались, когда и где использовать performSegueWithIdentifier метод в отличие от использования - prepareForSegue метод. И даже когда использовать tableView: didSelectRowAtIndexPath метод.

Позвольте мне вкратце объяснить здесь. Вы используете метод performSegueWithIdentifier, когда вы не контролировали перетаскивание сцены из одной сцены ViewController в другую в Storyboard. Таким образом, с помощью метод performSegueWithIdentifier позволит вам перемещаться между ViewController сцены до тех пор, как вы указать правильный идентификатор, который вы установили в раскадровке в разделе "Attributes Inspector. '

Теперь, если вы используете раскадровки вместо этого, вы бы не нужен Tableview: didSelectRowAtIndexPath метод. Что делает tableView: didSelectRowAtIndexPath метод does это то, что он сообщает делегату, что указанная строка теперь выбрана, и мы можем что-то сделать внутри ее тела кода (например, нажать изображение или текст на другую сцену ViewController, как вы пытаетесь делать). Но это становится излишним, когда вы используете segues. Все, что вам нужно сделать, это управления-сопротивлениеSEGUE из ячейки таблицы на вашем MyTableViewController сцены к вашей myViewController сцены.Выберите «Показать» и дать SEGUEидентификатор имя, как вы сделали «следующий». (Немного примечания стороны: если вы хотите функциональность в Назад кнопки для отображения на верхнем штурман панель при запуске приложения, вы просто вставить ваш MyTableViewController в UINavigationController, чтобы дать вам, что "Назад 'функциональные кнопки. с вашей MyTableViewController сценой, выбранной в раскадровке, Перейти в главное меню и выберите Editor >> Код In >> Navigation Controller. Тогда Walla !!)

Давайте теперь идите вперед и реализовывать нашу Tableview: prepareForSegue метод, как показано ниже:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { 
    if segue.identifier == "next" { 
     //Note that, originally, destinationViewController is of Type UIViewController and has to be casted as myViewController instead since that's the ViewController we trying to go to. 
     let destinationVC = segue.destinationViewController as! myViewController 


     if let indexPath = self.tableView.indexPathForSelectedRow{ 

      let selectedRow = ImageArray[indexPath.row] 

      destinationVC.imageName2 = selectedRow.0 
      destinationVC.textName2 = selectedRow.1 
} 

Из приведенного выше кода, убедитесь, что вы установите 'ImageName' и 'textName' как свойства в вашем myViewController класс первым, прежде чем вы сможете получить к ним доступ с 'destinationVC', который является теперь типа myViewController. Эти два свойства будут содержать данные, которые мы передаем от MyTableViewController класс до myViewController класс. И мы используем индекс массива для передачи данных этим двум свойствам соответственно.

Вы можете создать два IBOutlets для отображения изображения и текста, передавая этот набор «imageName2» и «textName2» свойство к точкам (или любому управлению UI по этому вопросу).

  • Теперь причина, почему вы должны установить свойство первым в myViewController класса, прежде чем передать их на или вокруг (т.е. к элемента пользовательского интерфейса, закрытию, другой VC и т.д.) является то, что, когда вы нажмете клетка Tableview из MyTableViewController сцена Segue на следующей ViewController сцены (т.е. ваш myViewController сцены), IOS не инстанцирован , что вторая сцена только пока. И поэтому вам нужно свойство для хранения данных , которые вы пытаетесь перенести на свой второй контроллер просмотра сцены первым, чтобы вы могли использовать позже, когда этот класс наконец загрузится.

Так что ваш myViewController класс должен выглядеть следующим образом:

import UIKit 

class myViewController : UIViewController { 

    //Your two strings to initially hold onto the data 
    //being passed to myViewController class 
var imageName2 : String? 
var textName2 : String? 

@IBOutlet weak var detailImageView: UIImageView! 
@IBOutlet weak var detailTextNameLabel: UITextField! 

override func viewDidLoad() { 
    super.viewDidLoad() 

    detailTextNameLabel.text = textName2! 

    if let image = UIImage(named: imageName2!) { 
     self.detailImageView.image = image 
    } 
} 

И это все!

вещи, чтобы отметить по маркировке и конвенций в Swift:

  • Начало именования классов с печатными буквами (т.е. класс ViewController() {})
  • Классы и свойства должны захватить смысл того, что они представлять. Я рекомендую вам изменить MyTableViewController и «myViewController» классов соответственно, чтобы отразить то, что они действительно средние или же (Вы можете пойти с „MainTableViewController“ и „DetailViewController“. Это будет делать только штраф).
  • Использовать маркировку camelToe для свойств и методов. (Я использовал ярлыки, которые вы указали в в своем вопросе, чтобы не слишком путать вас).

    Наслаждайтесь!

+0

HI! Спасибо за подробное объяснение, что помогает мне много! Я продолжу подключаться больше и надеюсь, что смогу многое продвинуться! Еще раз спасибо !!! :) –

+0

Нет проблем. Дайте мне знать, как все складывается для вас! Удачи! –

2

Это должно помочь: (. Где ImageView и TextView являются взгляды в вашем новом ViewController)

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { 
    if (segue.identifier == "next") { 
     let destination = segue.destinationViewController as! myViewController 
     destination.imageView.image = UIImage(named: ImageArray[tableView.indexPathForSelectedRow?.row]) 
     destination.textView.text = ImageArray[tableView.indexPathForSelectedRow?.row] 
    } 

}

Примечание:

  1. tableView.indexPathForSelectedRow?.row должно дать вам выбранная строка, как следует из названия, но может быть nil, поэтому c areful.
  2. Кроме того, соглашения об именах переменных Swift являются camelCase, поэтому imageView - правильный путь, а ImageView - неправильный.
+0

Благодарим за помощь! Но, хотя я написал совершенно правильно, он, похоже, не работает. Ошибки, которые я получил за последние две строки кода [tableView.indexPathForSelectedRow? .row], были: «Нельзя индексировать значение типа« [(String)] »с индексом типа« NSIndexPath? ». Как я могу чтобы исправить эти ошибки? Спасибо заранее! –

+0

Не согласны с тем, как вы инициализируете массив изображений и как его заполнять, чтобы я знал, как получить к нему доступ? – Acoop

+0

Я совсем не против! –

1

В скор 3 вы можете сделать что-то вроде этого:

В вашем MyTableViewController классе:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
{ 
    let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! UITableViewCell 

    // for imageview 

    var ImageView : UIImageView = cell.contentView.viewWithTag(1) as! UIImageView 
    ImageView.image = UIImage(named: ImageArray[indexPath.row]) 


    // for text 

    var TextView : UILabel = cell.contentView.viewWithTag(2) as! UILabel 
    ImageView.text = ImageArray[indexPath.row] 

    return cell 
} 

И в вашем методе didSelectRow:

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) 
{ 
    let nextVC = self.storyboard?.instantiateViewController(withIdentifier: "myViewController") as! myViewController 
    nextVC.myImgView.image = UIImame(named: ImageArray[indexPath.row]) 
    nextVC.myLabel.text = ImageArray[indexPath.row] 
    self.present(nextVC!, animated: true) 
} 

И в myViewController класс:

class myViewController: UIViewController 
{ 
    let myImageView = UIImageView() 
    let myLabel = UILabel() 
} 
Смежные вопросы