Як пройти файл ReadyForSegue: об’єкт


357

У мене багато анотацій у перегляді карти (з rightCalloutAccessoryкнопками). Кнопка виконає перехід від цього mapviewдо а tableview. Я хочу передати tableviewінший об’єкт (який містить дані) залежно від того, на яку кнопку натискали опис.

Наприклад: (повністю складено)

  • annotation1 (Austin) -> передайте дані obj 1 (стосується Austin)
  • annotation2 (Dallas) -> дані передачі obj 2 (стосується Далласа)
  • annotation3 (Х'юстон) -> передайте дані obj 3 і так далі ... (ви розумієте)

Я можу виявити, яку кнопку натискання натискали.

Я використовую prepareForSegue: для передачі даних obj до місця призначення ViewController. Оскільки я не можу змусити цей виклик взяти додатковий аргумент для потрібних мені даних, якими є елегантні способи досягнення такого ж ефекту (динамічні дані obj)?

Будь-яка порада буде вдячна.


Відповіді:


673

Просто захопіть посилання на контролер цільового перегляду в prepareForSegue:методі та передайте туди будь-які потрібні вам об’єкти. Ось приклад ...

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    // Make sure your segue name in storyboard is the same as this line
    if ([[segue identifier] isEqualToString:@"YOUR_SEGUE_NAME_HERE"])
    {
        // Get reference to the destination view controller
        YourViewController *vc = [segue destinationViewController];

        // Pass any objects to the view controller here, like...
        [vc setMyObjectHere:object];
    }
}

РЕВІЗАЦІЯ: Ви також можете використовувати performSegueWithIdentifier:sender:метод для активації переходу до нового виду на основі вибору або натискання кнопки.

Наприклад, подумайте, у мене було два контролери подання. Перша містить три кнопки, а друга повинна знати, яка з цих кнопок була натиснута перед переходом. Ви можете підключити кнопки до IBActionкоду, який використовує такий performSegueWithIdentifier:метод, як цей ...

// When any of my buttons are pressed, push the next view
- (IBAction)buttonPressed:(id)sender
{
    [self performSegueWithIdentifier:@"MySegue" sender:sender];
}

// This will get called too before the view appears
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([[segue identifier] isEqualToString:@"MySegue"]) {

        // Get destination view
        SecondView *vc = [segue destinationViewController];

        // Get button tag number (or do whatever you need to do here, based on your object
        NSInteger tagIndex = [(UIButton *)sender tag];

        // Pass the information to your destination view
        [vc setSelectedButton:tagIndex];
    }
}

EDIT: Демо-програму, яку я спочатку додав, зараз шість років, тому я її видалив, щоб уникнути плутанини.


Дякую, але я хочу це налаштувати [vc setMyObjectHere:object];динамічно. тобто obj1 для кнопки1, obj2 для кнопки2 Проблема в тому, що я не можу передавати аргумент. Чи існує спосіб цього?
шиплять

2
Я оновив свою посаду із завантаженим прикладом того, про що я говорю.
Саймон

що спрацювало! Дякую купу. В якості бічної записки підготуйтеForForSegue: має аргумент UIControl, який є батьківським класом UIButton (таким чином, зможе отримати тег): D
шиплять

Чи зателефонує на ReadyForSegue навіть тоді, коли ваш просто натискання на навігаційний контролер без розпаду розкадров?
zakdances

Це одна з найбільш ретельних відповідей, яку я коли-небудь бачив. Хороший зразок коду, вирішує проблему, пропонує завантажуваний зразок ... ух. Я вражений!
lewiguez

82

Іноді корисно уникати створення залежності часу компіляції між двома контролерами перегляду. Ось як це можна зробити, не піклуючись про тип контролера перегляду призначення:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.destinationViewController respondsToSelector:@selector(setMyData:)]) {
        [segue.destinationViewController performSelector:@selector(setMyData:) 
                                              withObject:myData];
    } 
}

Отже, поки контролер подання пункту призначення оголошує публічну власність, наприклад:

@property (nonatomic, strong) MyData *myData;

ви можете встановити це властивість у попередньому контролері перегляду, як я описав вище.


12
Це справді питання думки. У мене (поки що) не було ситуації, коли я не хотів контролювати контролери подання "щільно", хоча я ціную те, що ви говорите, і це може бути важливо за правильних обставин.
Саймон

2
@Simon: так, ви просто вибираєте підхід, який найкраще підходить для вас. Наприклад, у додатку, над яким я зараз працюю, наприклад, мій підхід має багато сенсу, оскільки я постійно додаю контролери перегляду, яким потрібен той самий об’єкт даних. Бути в змозі підключити їх за допомогою простого роздуму і знати, що вони отримають потрібні дані, це дуже зручно.
Macondo2Seattle

10
Це не питання думки, це просто неправильно :) Фраза "Прийнята відповідь - це не найкращий спосіб зробити це" неправильна. У ній має бути написано "У певних випадках вам потрібно це зробити ..."
Fattie

2
Я віддаю перевагу методу Саймона. Оскільки це скаже мені помилки під час компіляції. Наприклад, якщо я пропустив декларацію myData в контролері подання призначення, я буду знати це негайно. Але для вашого сценарію ваш підхід здається хорошим!
Абдуррахман Мубін Алі

14
Цей підхід абсолютно створює залежність, оскільки ви вимагаєте, щоб контролер подання місця призначення мав setMyData:. Це залежність. Те, що ви використовуєте селектор, щоб уникнути помилки компіляції, слід трактувати як слабкість вашого підходу, а не користь. Мене шокує, скільки розробників втратили концепцію, що компіляція помилок часу повинна віддавати перевагу помилкам під час виконання.
Нейт

21

У Swift 4.2 я би зробив щось подібне:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if let yourVC = segue.destination as? YourViewController {
        yourVC.yourData = self.someData
    }
}

Вам потрібно зателефонувати: `super.prepare (for: segue, sender: sender)`?
Ендрю К

16

У мене є клас відправника , як це

@class MyEntry;

@interface MySenderEntry : NSObject
@property (strong, nonatomic) MyEntry *entry;
@end

@implementation MySenderEntry
@end

Я використовую цей клас відправника для передачі об'єктів доprepareForSeque:sender:

-(void)didSelectItemAtIndexPath:(NSIndexPath*)indexPath
{
    MySenderEntry *sender = [MySenderEntry new];
    sender.entry = [_entries objectAtIndex:indexPath.row];
    [self performSegueWithIdentifier:SEGUE_IDENTIFIER_SHOW_ENTRY sender:sender];
}

-(void)prepareForSegue:(UIStoryboardSegue*)segue sender:(id)sender
{
    if ([[segue identifier] isEqualToString:SEGUE_IDENTIFIER_SHOW_ENTRY]) {
        NSAssert([sender isKindOfClass:[MySenderEntry class]], @"MySenderEntry");
        MySenderEntry *senderEntry = (MySenderEntry*)sender;
        MyEntry *entry = senderEntry.entry;
        NSParameterAssert(entry);

        [segue destinationViewController].delegate = self;
        [segue destinationViewController].entry = entry;
        return;
    }

    if ([[segue identifier] isEqualToString:SEGUE_IDENTIFIER_HISTORY]) {
        // ...
        return;
    }

    if ([[segue identifier] isEqualToString:SEGUE_IDENTIFIER_FAVORITE]) {
        // ...
        return;
    }
}

ми використовуємо prepareForSegue чи реалізуємо це, і припущення готується. ForSegue називається сам, тобто нам не потрібно робити щось на кшталт[self prepareForSegue]
Honey

15

Я натрапив на це питання, коли я намагався навчитися передавати дані від одного контролера перегляду до іншого. Мені потрібно щось наочне, щоб допомогти мені навчитися, тому ця відповідь є доповненням до інших, які вже є тут. Це трохи більш загальне, ніж первісне питання, але його можна пристосувати для роботи.

Цей основний приклад працює так:

введіть тут опис зображення

Ідея полягає в тому, щоб передати рядок з текстового поля в Контролері першого перегляду до мітки в Контролері другого перегляду.

Контролер першого виду

import UIKit

class FirstViewController: UIViewController {

    @IBOutlet weak var textField: UITextField!

    // This function is called before the segue
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {

        // get a reference to the second view controller
        let secondViewController = segue.destinationViewController as! SecondViewController

        // set a variable in the second view controller with the String to pass
        secondViewController.receivedString = textField.text!
    }

}

Контролер другого виду

import UIKit

class SecondViewController: UIViewController {

    @IBOutlet weak var label: UILabel!

    // This variable will hold the data being passed from the First View Controller
    var receivedString = ""

    override func viewDidLoad() {
        super.viewDidLoad()

        // Used the text from the First View Controller to set the label
        label.text = receivedString
    }

}

Пам'ятайте

  • Зробіть мозок control натиснувши на кнопку та перетягніть її на контролер другого виду.
  • Підключіть торгові точки для UITextFieldіUILabel .
  • Встановіть перший і другий контролери подання на відповідні файли Swift в IB.

Джерело

Як надсилати дані через segue (швидкий) (навчальний посібник YouTube)

Дивись також

Перегляд контролерів: передача даних уперед та повернення даних назад (повніша відповідь)


5

Для Swift використовуйте це,

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    var segueID = segue.identifier

    if(segueID! == "yourSegueName"){

        var yourVC:YourViewController = segue.destinationViewController as YourViewController

        yourVC.objectOnYourVC = setObjectValueHere!

    }
}

4

Я реалізував бібліотеку з категорією на UIViewController, яка спрощує цю операцію. В основному ви встановлюєте параметри, які ви хочете передати в NSDictionary, пов'язаний з елементом інтерфейсу, який виконує пошук. Він також працює з ручними сегами.

Наприклад, ви можете зробити

[self performSegueWithIdentifier:@"yourIdentifier" parameters:@{@"customParam1":customValue1, @"customValue2":customValue2}];

для ручної розвідки або створити кнопку із сегею та користуватися

[button setSegueParameters:@{@"customParam1":customValue1, @"customValue2":customValue2}];

Якщо контролер подання пункту призначення не кодує значення ключа-значення для ключа, нічого не відбувається. Він також працює з ключовими значеннями (корисно для розмотувальних мов). Перевірте це https://github.com/stefanomondino/SMQuickSegue


2

Моє рішення подібне.

// In destination class: 
var AddressString:String = String()

// In segue:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
   if (segue.identifier == "seguetobiddetailpagefromleadbidder")
    {
        let secondViewController = segue.destinationViewController as! BidDetailPage
        secondViewController.AddressString = pr.address as String
    }
}

1

Просто використовуйте цю функцію.

 override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    let index = CategorytableView.indexPathForSelectedRow
    let indexNumber = index?.row
    let VC = segue.destination as! DestinationViewController
   VC.value = self.data

}

0

Я використав це рішення, щоб я міг тримати виклик segue та передачу даних в межах однієї функції:

private var segueCompletion : ((UIStoryboardSegue, Any?) -> Void)?

func performSegue(withIdentifier identifier: String, sender: Any?, completion: @escaping (UIStoryboardSegue, Any?) -> Void) {
    self.segueCompletion = completion;
    self.performSegue(withIdentifier: identifier, sender: sender);
    self.segueCompletion = nil
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    self.segueCompletion?(segue, sender)
}

Випадок використання буде приблизно таким:

func showData(id : Int){
    someService.loadSomeData(id: id) {
        data in
        self.performSegue(withIdentifier: "showData", sender: self) {
            storyboard, sender in
            let dataView = storyboard.destination as! DataView
            dataView.data = data
        }
    }
}

Це, здається, працює для мене, проте я не на 100% впевнений, що функції виконання та підготовки завжди виконуються в одній темі.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.