Як пройти файл 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.