iOS
Pasando datos entre los controladores de vista
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:
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.
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:
- Usted puede invocar el "código duro":
self.performSegueWithIdentifier("YourCustomIdentifier", sender: self)
que hará el desenlace por usted cada vez queperformSegueWithIdentifier
. - 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":
Suelte y tendrá la opción de elegir su método de desenrollado personalizado:
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)")
}
}
}