Buscar..


Usando Segues (pasando datos hacia adelante)

Para pasar los datos del controlador de vista actual al siguiente controlador de vista nuevo (no un controlador de vista anterior) usando segues, primero cree un segmento con un identificador en el guión gráfico relevante. Reemplace el método prepareForSegue su controlador de vista actual. Dentro del método, compruebe el segmento que acaba de crear por su identificador. Convierta el controlador de vista de destino y pase los datos al mismo estableciendo las propiedades en el controlador de vista descendente.

Estableciendo un identificador para un segue:

Inspector de atributos para una segue

Los segmentos se pueden realizar programáticamente o usando el evento de acción de botón establecido en el guión gráfico con ctrl + arrastrar al controlador de vista de destino. Puede solicitar un segue programáticamente, cuando sea necesario, utilizando el identificador de segue en el controlador de vista:

C objetivo

- (void)showDetail {
    [self performSegueWithIdentifier:@"showDetailingSegue" sender:self];        
}

Rápido

func showDetail() {
    self.performSegue(withIdentifier: "showDetailingSegue", sender: self)
}

Puede configurar la carga útil segue en la versión prepareForSegue método prepareForSegue . Puede establecer las propiedades requeridas antes de que se cargue el controlador de vista de destino.

C objetivo

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if([segue.identifier isEqualToString:@"showDetailingSegue"]){
        DetailViewController *controller = (DetailViewController *)segue.destinationViewController;
        controller.isDetailingEnabled = YES;
    }
}

Rápido

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "showDetailingSegue" {
        let controller = segue.destinationViewController as! DetailViewController
        controller.isDetailingEnabled = true
    }    
}

DetailViewController es el nombre del segundo controlador de vista e isDetailingEnabled es una variable pública en ese controlador de vista.

Para expandir este patrón, puede tratar un método público en DetailViewController como un pseudoinicializador, para ayudar a inicializar cualquier variable requerida. Esto auto documentará las variables que deben configurarse en DetailViewController sin tener que leer su código fuente. También es un lugar práctico para poner valores por defecto.

C objetivo

- (void)initVC:(BOOL *)isDetailingEnabled {
    self.isDetailingEnabled = isDetailingEnabled
}

Rápido

func initVC(isDetailingEnabled: Bool) {
    self.isDetailingEnabled = isDetailingEnabled
}

Usando el patrón delegado (pasando los datos de vuelta)

Para pasar los datos del controlador de vista actual al controlador de vista anterior, puede usar el patrón delegado.

introduzca la descripción de la imagen aquí

En este ejemplo, se supone que ha realizado un segmento en el Creador de interfaces y que configuró el identificador de showSecondViewController en showSecondViewController . Las salidas y acciones también deben estar conectadas a los nombres en el siguiente código.

Primer controlador de vista

El código del First View Controller es

Rápido

class FirstViewController: UIViewController, DataEnteredDelegate {

    @IBOutlet weak var label: UILabel!
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "showSecondViewController", let secondViewController = segue.destinationViewController as? SecondViewController  {
            secondViewController.delegate = self
        }
    }

    // required method of our custom DataEnteredDelegate protocol
    func userDidEnterInformation(info: String) {
        label.text = info
        navigationController?.popViewControllerAnimated(true)
    }
}

C objetivo

@interface FirstViewController : UIViewController <DataEnteredDelegate>
@property (weak, nonatomic) IBOutlet UILabel *label;
@end

@implementation FirstViewController
- (void)viewDidLoad {
    [super viewDidLoad];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    SecondViewController *secondViewController = segue.destinationViewController;
    secondViewController.delegate = self;

}
-(void)userDidEnterInformation:(NSString *)info {
    _label.text = info
    [self.navigationController popViewControllerAnimated:YES];
}
@end

Tenga en cuenta el uso de nuestro protocolo personalizado DataEnteredDelegate .

Segundo controlador y protocolo de vista

El código para el segundo controlador de vista es

Rápido

// protocol used for sending data back
protocol DataEnteredDelegate: class {
    func userDidEnterInformation(info: String)
}

class SecondViewController: UIViewController {

    // making this a weak variable so that it won't create a strong reference cycle
    weak var delegate: DataEnteredDelegate?
    
    @IBOutlet weak var textField: UITextField!

    @IBAction func sendTextBackButton(sender: AnyObject) {
        
        // call this method on whichever class implements our delegate protocol (the first view controller)
        delegate?.userDidEnterInformation(textField.text ?? "")
    }
}

C objetivo

@protocol DataEnteredDelegate <NSObject>
-(void)userDidEnterInformation:(NSString *)info;
@end

@interface SecondViewController : UIViewController 
@property (nonatomic) id <DataEnteredDelegate> delegate;
@property (weak, nonatomic) IBOutlet UITextField *textField;
@end

@implementation SecondViewController
- (void)viewDidLoad {
    [super viewDidLoad];
}

- (IBAction) sendTextBackButton:(id)sender{
    [_delegate userDidEnterInformation:textField.text];
}
@end

Tenga en cuenta que el protocol está fuera de la clase View Controller.

Pasando los datos hacia atrás usando desenrollar para segue

A diferencia de Segue, que le permite pasar datos "hacia adelante" desde el controlador de vista actual al controlador de vista de destino:

(VC1) -> (VC2)

Usando "desenrollar" puede hacer lo contrario, pasar los datos desde el controlador de vista actual o de destino a su controlador de vista actual:

(VC1) <- (VC2)

NOTA : Preste atención a que el uso del desenrollado le permite pasar los datos primero y luego el controlador de vista actual (VC2) se desasignará.

Aquí está cómo hacerlo:

Primero, deberá agregar la siguiente declaración en el controlador de vista de presentación (VC1), que es el controlador de vista al que queremos pasar los datos:

@IBAction func unwindToPresentingViewController(segue:UIStoryboardSegue)

Lo importante es usar el unwind prefijo, esto "informa" a Xcode de que este es un método de desenrollado que le da la opción de usarlo también en el guión gráfico.

Luego, deberá implementar el método, se ve casi igual que un segmento real:

@IBAction func unwindToPresentingViewController(segue:UIStoryboardSegue)
{
    if segue.identifier == "YourCustomIdentifer"
    {
        if let VC2 = segue.sourceViewController as? VC2
        {
            //    Your custom code in here to access VC2 class member
        }

Ahora tienes 2 opciones para invocar las llamadas de desvinculación:

  1. Usted puede invocar el "código duro": self.performSegueWithIdentifier("YourCustomIdentifier", sender: self) que hará el desenlace por usted cada vez que performSegueWithIdentifier .
  2. Puede vincular el método de desenrollado utilizando el storyboard a su objeto "Salir": presione Ctrl + arrastre el botón que desea invocar al método de desenrollar, al objeto "Salir":

introduzca la descripción de la imagen aquí

Suelte y tendrá la opción de elegir su método de desenrollado personalizado:

introduzca la descripción de la imagen aquí

Pasar datos utilizando cierres (devolver datos)

En lugar de usar el patrón delegado , que divide la implementación en varias partes de la clase UIViewController , incluso puede usar closures para pasar los datos hacia adelante y hacia atrás. Suponiendo que está utilizando UIStoryboardSegue , en el método prepareForSegue puede configurar fácilmente el nuevo controlador en un solo paso

final class DestinationViewController: UIViewController {
    var onCompletion: ((success: Bool) -> ())?

    @IBAction func someButtonTapped(sender: AnyObject?) {
        onCompletion?(success: true)
    }
}

final class MyViewController: UIViewController {
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    
        guard let destinationController = segue.destinationViewController as? DestinationViewController else { return }
    
        destinationController.onCompletion = { success in
            // this will be executed when `someButtonTapped(_:)` will be called
            print(success)
        }
    }
}

Este es un ejemplo de uso y es mejor usarlo en Swift, la sintaxis del bloque Objective-C no es tan fácil hacer que el código sea más legible

Usando el cierre de devolución de llamada (bloque) pasando los datos de vuelta

Este tema es un problema clásico en el desarrollo de iOS, y su solución es variada, como lo muestra otro ejemplo. En este ejemplo, mostraré otro uso común diario: pasar datos usando el closure adaptando el ejemplo de delegate pattern en esta página al closure devolución de llamada.

Una cosa es que este método es superior al delegate pattern lugar de dividir el código de configuración en dos lugares diferentes (mire el ejemplo de delegado en esta página, prepareForSegue , userDidEnterInformation ) en lugar de reunirlos (solo en prepareForSegue , lo mostraré)

Comenzar desde Second View Controller

debemos averiguar cómo usar la devolución de llamada, luego podemos escribirla, es por eso que comenzamos desde el segundo controlador de vista, ya que es donde usamos la devolución de llamada: cuando recibimos la nueva entrada de texto, llamamos a nuestra devolución de llamada, utilizando el parámetro de devolución de llamada como medio Para pasar los datos de vuelta al primer ViewController, note que dije que usando el parámetro de devolución de llamada, esto es muy importante, los principiantes (como yo) siempre pasan esto por alto y no saben por dónde empezar a escribir el cierre de la devolución de llamada correctamente.

así que en este caso, sabemos que nuestra devolución de llamada solo toma un parámetro: texto y su tipo es String , String y hagámoslo propiedad ya que necesitamos poblar desde nuestro primer controlador de vista

Solo comento toda la parte del delegate y la guardo para comparar.

class SecondViewController: UIViewController {

    //weak var delegate: DataEnteredDelegate? = nil
    var callback: ((String?)->())?
    
    @IBOutlet weak var textField: UITextField!

    @IBAction func sendTextBackButton(sender: AnyObject) {
        
        //delegate?.userDidEnterInformation(textField.text!)
        callback?(input.text)
        
        self.navigationController?.popViewControllerAnimated(true)
    }
}

Termina la primera vista del controlador

todo lo que tiene que hacer es pasar el cierre de devolución de llamada, y hemos terminado, el cierre hará el trabajo futuro por nosotros, ya que ya lo configuramos en el segundo controlador de vista

Mira cómo hace que nuestro código sea más corto en comparación con el delegate pattern

//no more DataEnteredDelegate
class FirstViewController: UIViewController {

    @IBOutlet weak var label: UILabel!
    
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if segue.identifier == "showSecondViewController" {
            let secondViewController = segue.destinationViewController as! SecondViewController
            //secondViewController.delegate = self
            secondViewController.callback = { text in self.label.text = text }
        }
    }

    // required method of our custom DataEnteredDelegate protocol
    //func userDidEnterInformation(info: String) {
    //    label.text = info
    //}
}

y en el último, tal vez alguno de ustedes se confundirá al ver que solo pasamos los datos (cierre en este caso) solo de una manera, desde el primer controlador de vista al segundo, sin regresar directamente del segundo controlador de vista, ¿cómo podemos ¿Considerarlo como una herramienta de comunicación? tal vez realmente debería ejecutarlo y probarlo usted mismo, todo lo que diré es el parámetro , ¡es el parámetro de cierre de devolución de llamada que pasa los datos de vuelta!

Asignando propiedad (Pasando datos adelante)

Puede pasar datos directamente asignando la propiedad del siguiente controlador de vista antes de presionarlo o presentarlo.

class FirstViewController: UIViewController {

    func openSecondViewController() {

        // Here we initialize SecondViewController and set the id property to 492
        let secondViewController = SecondViewController()
        secondViewController.id = 492

        // Once it was assign we now push or present the view controller
        present(secondViewController, animated: true, completion: nil)
    }

}

class SecondViewController: UIViewController {
    
    var id: Int?

    override func viewDidLoad() {
        super.viewDidLoad()

        // Here we unwrapped the id and will get the data from the previous view controller.
        if let id = id {
            print("Id was set: \(id)")
        }
    }
}


Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow