Как пройти prepareForSegue: объект

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

Например: (полностью выдуманный)

  • annotation1 (Остин) -> передать данные объекта 1 (относится к Остину)
  • annotation2 (Даллас) -> передать данные объекта 2 (относится к Далласу)
  • annotation3 (Хьюстон) -> передать данные obj 3 и так далее... (вы поняли)

Я могу определить, какая кнопка была нажата.

я использую prepareForSegue: передать данные объекта в пункт назначения ViewController, Поскольку я не могу заставить этот вызов принять дополнительный аргумент для нужного мне объекта данных, каковы некоторые изящные способы достижения того же эффекта (динамический объект данных)?

Любой совет будет оценен.

10 ответов

Решение

Просто возьмите ссылку на целевой контроллер вида в 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];
    }
}

РЕДАКТИРОВАТЬ: демо-приложение, которое я первоначально приложил, теперь шесть лет, поэтому я удалил его, чтобы избежать путаницы.

Принятый ответ - не лучший способ сделать это, потому что он создает ненужную зависимость во время компиляции между двумя контроллерами представления. Вот как вы можете сделать это, не заботясь о типе контроллера представления назначения:

- (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;

Вы можете установить это свойство в предыдущем контроллере представления, как я описал выше.

В Swift 4.2 я бы сделал что-то подобное:

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

У меня есть класс отправителя, как это

@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;
    }
}

Я столкнулся с этим вопросом, когда пытался научиться передавать данные из одного View Controller в другой. Мне нужно что-то визуальное, чтобы помочь мне учиться, поэтому этот ответ является дополнением к другим уже здесь. Это немного более общий вопрос, чем первоначальный вопрос, но его можно адаптировать к работе.

Этот базовый пример работает так:

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

Идея состоит в том, чтобы передать строку из текстового поля в первом контроллере представления метке во втором контроллере представления.

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

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
    }

}

Запомни

  • Сделайте переход, нажав на кнопку и перетащив ее в контроллер второго вида.
  • Подключите розетки для UITextField и UILabel,
  • Установите первый и второй View Controllers для соответствующих файлов Swift в IB.

Источник

Как отправить данные через segue (swift) (учебник YouTube)

Смотрите также

View Controllers: передача данных вперед и передача данных назад (более полный ответ)

Для 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!

    }
}

Я реализовал библиотеку с категорией на UIViewController, которая упрощает эту операцию. По сути, вы устанавливаете параметры, которые хотите передать, в NSDictionary, связанном с элементом пользовательского интерфейса, который выполняет переход. Работает и с ручными переходами.

Например, вы можете сделать

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

для ручного перехода или создать кнопку с переходом и использовать

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

Если контроллер представления назначения не совместим с ключом для кодирования значения ключа, ничего не происходит. Он также работает со значениями ключа (полезно для раскручивания сегментов). Проверьте это здесь https://github.com/stefanomondino/SMQuickSegue

Мое решение похоже.

// 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
    }
}

Просто используйте эту функцию.

 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

}

Я использовал это решение, чтобы сохранить вызов 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%, что функции выполнения и подготовки всегда выполняются в одном потоке.

Другие вопросы по тегам