2014-12-13 2 views
6

Я пытаюсь изучить Swift, и я пытаюсь разработать знаменитое приложение для заметок.ПодготавливаетForSegue правильный путь передачи значения между контроллерами вида

Существует массив, привязанный к представлению таблицы и другой вид для добавления заметок. Во втором представлении textfieldshouldreturn событие запускает segue и возвращается к таблице.

Я хотел узнать, правильно ли это. Потому что, делая это, я манипулирую переменной в другом контроллере представления. Я не мастер MVC, но я чувствовал, что это неправильно. Вот мой фрагмент кода:

func textFieldShouldReturn(textField: UITextField) -> Bool { 

    self.performSegueWithIdentifier("backSegue", sender: self) 
    return true 
} 

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { 
    if(segue.identifier == "backSegue"){ 
     let navController = segue.destinationViewController as UINavigationController; 
     let myController = navController.topViewController as NotesTableViewController; 
     if(self.ourTextField?.text != nil || self.ourTextField?.text != ""){ 
      myController.notes.append(self.ourTextField?.text ?? ""); 
     } 

    } 
} 

Спасибо.

+0

Почему вы * чувствуете себя не так? Это правильный путь. Контроллеры ara используются для управления данными и представлениями этих данных, поэтому, когда segue push (или pop) другой диспетчер представлений, разумно передавать некоторые данные между источником и получателем. –

+0

Это, безусловно, очень распространенный способ передачи данных между контроллерами представлений, и вы не должны беспокоиться о его использовании. Множество [уважаемых разработчиков] (http://oleb.net/blog/2012/02/passing-data-between-view-controllers/) делают это. Это не единственный путь, но есть и другие варианты. Насколько я знаю, Swift не приносит ничего особенного в таблицу в этом отношении, поэтому вы должны проверить [существующий вопрос Objective C] (http://stackoverflow.com/questions/5210535/passing-data-between -view-контроллеры). –

ответ

7

Ваш вопрос не совсем о prepareForSegue, но связь между контроллерами. Причина, по которой ваш дизайн «чувствует себя не так», заключается в том, что он есть. Проблема в том, что ваш контроллер записи заметки знает слишком много о контроллере представления, который использует его, потому что он непосредственно манипулирует переменной из вызывающего контроллера. Чтобы напрямую манипулировать переменной, он должен знать класс вызывающего.

Почему это проблема? Это делает ваш блокнот для заметок менее многоразовым. Если вы правильно пишете контроллер записи заметок, вы можете повторно использовать его в других приложениях. Чтобы сделать его многоразовым, вам нужно отделить контроллер записи заметки от вызывающего - он не должен знать, кто именно его вызывает.

Итак, вопрос будет, как передать данные обратно вызывающему, если я не знаю, кто звонил мне? Ответ Делегация.

Делегация работает следующим образом:

  1. Вы создаете протокол, описывающий метод или методы, которые реализатор этого протокола будет реализовать. В вашем случае вы можете использовать протокол, например NoteWriterDelegate, который реализует метод takeNote(note: String).

    protocol NoteWriterDelegate { 
        func takeNote(note: String) 
    } 
    

    Определите это в файле вместе с контроллером просмотра заметок.

  2. Ваш автор банкнота будет иметь дополнительный указатель делегата:

    weak var delegate: NoteWriterDelegate? 
    
  3. Вы должны объявить свой первый контроллер представления в качестве NoteWriterDelegate:

    class ViewController: UITableViewController, NoteWriterDelegate 
    
  4. А затем реализовать требуемое метод в вашем первом контроллере:

    func takeNote(note: String) { 
        notes.append(note) 
    } 
    
  5. При вызове prepareForSegue в подготовке для перемещения к, записке писать вид контроллер, вы передаете себя в качестве делегата:

    destinationViewController.delegate = self 
    
  6. В контроллере представления примечания записи, если у вас есть примечание, чтобы пройти назад вызывающий абонент, вы звоните takeNote на делегат:

    delegate?.takeNote(self.ourTextField?.text ?? "") 
    

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

2

Я бы порекомендовал передавать данные через prepareForSegue в большинстве случаев. Это довольно просто настроить и легко понять.

Однако я бы порекомендовал никогда не обновлять элементы интерфейса (метки, текстовые поля и т. Д.) Непосредственно на целевом представлении. На мой взгляд, это плохая связь, которая создает много проблем.

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

Делегирование - действительный подход, но я считаю, что это слишком много для большинства ситуаций. Это требует большей настройки и более абстрактно. Эта абстракция не требуется во многих отношениях контроллера. Если вы обнаружите, что вам нужно повторно использовать контроллер вида, вы всегда сможете реорганизовать его позже.

2

Я не считаю, что prepareSegue является идеальным способом передачи данных между контроллерами представлений ... по крайней мере, не напрямую.

Я разделяю вашу озабоченность по поводу использования prepareForSegue для передачи значений между контроллерами представлений. Контроллер представления источника не должен знать ничего о контроллере представления назначения (и, наоборот, в этом отношении). Идеально Контроллеры просмотра должны быть отдельными островами без видимости друг с другом.

Чтобы обратиться к муфте, которую, по-видимому, поощряют раскадровки, я часто использовал какую-то форму mediator pattern для передачи данных между контроллерами представлений. Вот довольно хорошее сообщение в блоге о том, как реализовать версию этого шаблона вокруг раскадровки: http://coding.tabasoft.it/ios/mediator-pattern-in-swift/. Как всегда, этот шаблон может быть не самым подходящим для всех ситуаций, но я считаю, что это было хорошим решением во многих моих прошлых проектах.

В принципе, как шаблон посредника будет работать в рамках парадигмы раскадровки, так это то, что в каждом методе метода prepareForSegue контроллера view объект Segue передается объекту-посреднику. Контроллеру просмотра не волнует, что внутри или куда идет навигационная система; он просто знает, что это не будет видно. Посредник, который только что передал объект segue (содержащий контроллеры представления источника и получателя), затем отвечает за передачу данных между контроллерами представления источника и получателя.

Используя этот шаблон, каждый контроллер вида блаженно не знает о существовании другого. С другой стороны, класс медиатора должен знать о связях между контроллерами представлений (и интерфейсами диспетчера представлений) в пути навигации. Очевидно, что если изменения навигации или сами контроллеры представлений меняются, класс посредника должен будет корректироваться. Каждый контроллер точки зрения, однако, не должен зависеть друг от друга и поэтому не нуждается в обновлении, чтобы учитывать изменения в пути навигации или изменения в других контроллерах представлений вдоль этого пути навигации.

0

Это не «правильный» путь, но это правильный путь. Особенно в приложениях для раскадровки.

Вот альтернативный способ передачи значения и вызова представления.

var myNewVC = NewViewController() 
myNewVC.data = self 
navigationController?.presentViewController(myNewVC, animated: true, completion: nil) 
Смежные вопросы