mvc - mvvm ios




Passaggio dei dati tra i controller di visualizzazione (20)

veloce

Ci sono tonnellate e tonnellate di spiegazioni qui e in giro StackOverflow, ma se sei un principiante solo cercando di ottenere qualcosa di base per lavorare, prova a guardare questo tutorial di YouTube (è quello che mi ha aiutato a capire finalmente come farlo).

Trasmissione dei dati al successivo controller di visualizzazione

Quello che segue è un esempio basato sul video. L'idea è di passare una stringa dal campo di testo in First View Controller all'etichetta in Second View Controller.

Crea il layout dello storyboard in Interface Builder. Per fare il seguito, basta fare clic sul pulsante e trascinare sul secondo controller di visualizzazione.

First View Controller

Il codice per il controller First View è

import UIKit

class FirstViewController: UIViewController {

    @IBOutlet weak var textField: UITextField!

    // This function is called before the segue
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

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

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

}

Secondo View Controller

E il codice per il secondo controller di visualizzazione è

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
    }

}

Non dimenticare

  • Collegare le uscite per UITextField e UILabel .
  • Impostare il primo e il secondo controller di visualizzazione sui file Swift appropriati in IB.

Passare i dati al controller di visualizzazione precedente

Per passare i dati dal secondo controller della vista al primo controller della vista, si utilizza un protocollo e un delegato . Questo video è una passeggiata molto chiara attraverso questo processo:

Quello che segue è un esempio basato sul video (con alcune modifiche).

Crea il layout dello storyboard in Interface Builder. Ancora una volta, per eseguire il seguito, basta trascinare il controllo dal pulsante a Second View Controller. Imposta l'identificatore di showSecondViewController per showSecondViewController . Inoltre, non dimenticare di collegare le prese e le azioni utilizzando i nomi nel seguente codice.

First View Controller

Il codice per il controller First View è

import UIKit

class FirstViewController: UIViewController, DataEnteredDelegate {

    @IBOutlet weak var label: UILabel!

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "showSecondViewController" {
            let secondViewController = segue.destination as! SecondViewController
            secondViewController.delegate = self
        }
    }

    func userDidEnterInformation(info: String) {
        label.text = info
    }
}

Nota l'uso del nostro protocollo personalizzato DataEnteredDelegate .

Secondo View Controller and Protocol

Il codice per il secondo controller di vista è

import UIKit

// 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? = nil

    @IBOutlet weak var textField: UITextField!

    @IBAction func sendTextBackButton(sender: AnyObject) {

        // call this method on whichever class implements our delegate protocol
        delegate?.userDidEnterInformation(info: textField.text!)

        // go back to the previous view controller
        _ = self.navigationController?.popViewController(animated: true)
    }
}

Si noti che il protocol è al di fuori della classe View Controller.

Questo è tutto. Eseguendo l'app ora dovresti essere in grado di inviare i dati dal secondo controller della vista al primo.

Sono nuovo di iOS e Objective-C e dell'intero paradigma MVC e sono bloccato con quanto segue:

Ho una visione che funge da modulo di inserimento dati e voglio dare all'utente la possibilità di selezionare più prodotti. I prodotti sono elencati su un'altra vista con UITableViewController e ho abilitato selezioni multiple.

La mia domanda è, come posso trasferire i dati da una vista a un'altra? UITableView le selezioni su UITableView in un array, ma come faccio a passare nuovamente alla visualizzazione del modulo di inserimento dati precedente in modo che possa essere salvata insieme agli altri dati a Core Data alla sottomissione del modulo?

Ho navigato in giro e ho visto alcune persone dichiarare un array nel delegato dell'app. Leggo qualcosa su Singletons ma non capisco cosa siano e leggo qualcosa sulla creazione di un modello di dati.

Quale sarebbe il modo corretto di eseguire questo e come dovrei farlo?


Ci sono alcune buone informazioni in molte delle risposte fornite, ma nessuna risolve completamente la domanda.

La domanda riguarda il passaggio delle informazioni tra i controller della vista. L'esempio specifico fornito richiede di passare informazioni tra le viste, ma vista la novità auto-dichiarata per iOS, il poster originale probabilmente intendeva tra viewControllers, non tra le viste (senza alcun coinvolgimento da ViewControllers). Sembra che tutte le risposte si concentrino su due controller di vista, ma cosa succederebbe se l'app dovesse evolvere per coinvolgere più di due controller di visualizzazione nello scambio di informazioni?

Il poster originale ha anche chiesto di Singletons e l'uso dell'AppDelegate . Queste domande devono essere risolte.

Per aiutare chiunque altro a guardare questa domanda, che vuole una risposta completa, cercherò di fornirla.

Scenari di applicazione

Piuttosto che avere una discussione altamente ipotetica e astratta, aiuta ad avere in mente applicazioni concrete. Per aiutare a definire una situazione con controller a due viste e una situazione di controller con più di due visualizzazioni, definirò due scenari concreti di applicazione.

Scenario uno: i massimo due controller di visualizzazione hanno bisogno di condividere le informazioni. Vedi il diagramma uno.

Ci sono due controller di vista nell'applicazione. C'è un ViewControllerA (Modulo di inserimento dati) e Visualizza il controller B (Elenco prodotti). Gli articoli selezionati nell'elenco dei prodotti devono corrispondere agli articoli visualizzati nella casella di testo nel modulo di inserimento dati. In questo scenario, ViewControllerA e ViewControllerB devono comunicare direttamente tra loro e nessun altro controller di visualizzazione.

Scenario due : più di due controller di visualizzazione devono condividere le stesse informazioni. Vedi il diagramma due.

Ci sono quattro controller di vista nell'applicazione. È un'applicazione basata su schede per la gestione dell'inventario domestico. Tre controller di visualizzazione presentano viste filtrate in modo diverso degli stessi dati:

  • ViewControllerA - Articoli di lusso
  • ViewControllerB - Articoli non assicurati
  • ViewControllerC - Inventario casa intero
  • ViewControllerD - Aggiungi nuovo modulo articolo

Ogni volta che un singolo articolo viene creato o modificato, deve anche sincronizzarsi con gli altri controller di visualizzazione. Ad esempio, se aggiungiamo una barca in ViewControllerD, ma non è ancora assicurata, la barca deve apparire quando l'utente va a ViewControllerA (Oggetti di lusso), e anche ViewControllerC (Tutto l'inventario della casa), ma non quando l'utente va a ViewControllerB (articoli non assicurati). Dobbiamo preoccuparci non solo dell'aggiunta di nuovi elementi, ma anche dell'eliminazione di elementi (che possono essere consentiti da uno qualsiasi dei quattro controller di vista), o della modifica di elementi esistenti (che possono essere consentiti dal "Aggiungi modulo di nuovo elemento", che si ripropone lo stesso per la modifica).

Poiché tutti i controller di visualizzazione devono condividere gli stessi dati, tutti e quattro i controller di vista devono rimanere sincronizzati e pertanto è necessario un qualche tipo di comunicazione con tutti gli altri controller di visualizzazione, ogni volta che un singolo controller di visualizzazione modifica i dati sottostanti. Dovrebbe essere abbastanza ovvio che non vogliamo che ogni controller di visualizzazione comunichi direttamente con l'altro controller di visualizzazione in questo scenario. Nel caso non sia ovvio, considera se avevamo 20 diversi controller di visualizzazione (anziché solo 4). Quanto sarebbe difficile e soggetto a errori comunicare a ciascuno degli altri 19 controller di visualizzazione in qualsiasi momento in cui un controller di visualizzazione ha apportato una modifica?

Le soluzioni: delegati e modello di osservatore e singleton

Nello scenario uno, abbiamo diverse soluzioni praticabili, come hanno dato altre risposte

  • segues
  • delegati
  • impostazione delle proprietà direttamente sui controller della vista
  • NSUserDefaults (in realtà una scelta sbagliata)

Nello scenario due, abbiamo altre soluzioni praticabili:

  • Modello di osservatore
  • Singletons

Un singleton è un'istanza di una classe, quell'istanza è l'unica istanza esistente durante la sua vita. Un singleton prende il nome dal fatto che è l'unica istanza. Normalmente gli sviluppatori che usano i singleton hanno metodi di classe speciali per accedervi.

+ (HouseholdInventoryManager*) sharedManager; {
    static dispatch_once_t onceQueue;
    static HouseholdInventoryManager* _sharedInstance;

    // dispatch_once is guaranteed to only be executed once in the
    // lifetime of the application
    dispatch_once(&onceQueue, ^{
        _sharedInstance = [[self alloc] init];
    });
    return _sharedInstance;
}

Ora che capiamo cos'è un singleton, discutiamo di come un singleton si adatta allo schema dell'osservatore. Il modello di osservatore viene utilizzato per un oggetto per rispondere alle modifiche di un altro oggetto. Nel secondo scenario, abbiamo quattro diversi controller di visualizzazione, che tutti desiderano conoscere le modifiche ai dati sottostanti. I "dati sottostanti" dovrebbero appartenere a una singola istanza, un singleton. Il "conoscere i cambiamenti" si ottiene osservando le modifiche apportate al singleton.

L'applicazione di inventario casa avrebbe una singola istanza di una classe progettata per gestire un elenco di articoli di inventario. Il gestore gestiva una raccolta di articoli per la casa. La seguente è una definizione di classe per il gestore dati:

#import <Foundation/Foundation.h>

@class JGCHouseholdInventoryItem;

@interface HouseholdInventoryManager : NSObject
/*!
 The global singleton for accessing application data
 */
+ (HouseholdInventoryManager*) sharedManager;


- (NSArray *) entireHouseholdInventory;
- (NSArray *) luxuryItems;
- (NSArray *) nonInsuredItems;

- (void) addHouseholdItemToHomeInventory:(JGCHouseholdInventoryItem*)item;
- (void) editHouseholdItemInHomeInventory:(JGCHouseholdInventoryItem*)item;
- (void) deleteHoueholdItemFromHomeInventory:(JGCHouseholdInventoryItem*)item;
@end

Quando la raccolta di articoli di inventario domestici cambia, i controller di visualizzazione devono essere informati di questa modifica. La definizione della classe sopra non rende evidente come ciò avverrà. Dobbiamo seguire lo schema dell'osservatore. I controllori della vista devono osservare formalmente il SharedManager. Esistono due modi per osservare un altro oggetto:

  • Key-Value-Observing (KVO)
  • NSNotificationCenter.

Nello scenario due, non abbiamo una singola proprietà di HouseholdInventoryManager che potrebbe essere osservata usando KVO. Poiché non abbiamo una singola proprietà che sia facilmente osservabile, il modello di osservatore, in questo caso, deve essere implementato utilizzando NSNotificationCenter. Ognuno dei quattro controller di visualizzazione si iscriverebbe alle notifiche e il gestore condiviso invierà notifiche al centro notifiche quando appropriato. Il gestore dell'inventario non ha bisogno di sapere nulla sui controllori delle viste o sulle istanze di altre classi che potrebbero essere interessate a sapere quando cambia la collezione di articoli di inventario; NSNotificationCenter si occupa di questi dettagli di implementazione. I View Controller si limitano a sottoscrivere le notifiche e il gestore dati pubblica semplicemente le notifiche.

Molti programmatori principianti traggono vantaggio dal fatto che esiste sempre esattamente un delegato dell'applicazione nel corso della vita dell'applicazione, che è accessibile a livello globale. I programmatori principianti utilizzano questo fatto per inserire oggetti e funzionalità nell'appDelegate come comodità per l'accesso da qualsiasi altra parte dell'applicazione. Solo perché l'AppDelegate è un singleton non significa che dovrebbe sostituire tutti gli altri singleton. Questa è una cattiva pratica in quanto pone troppo peso su una classe, rompendo le buone pratiche orientate agli oggetti. Ogni classe dovrebbe avere un ruolo chiaro che è facilmente spiegabile, spesso solo con il nome della classe.

Ogni volta che il tuo delegato dell'applicazione inizia a gonfiarsi, inizia a rimuovere la funzionalità in singleton. Ad esempio, lo stack di dati principali non deve essere lasciato in AppDelegate, ma deve essere inserito nella propria classe, una classe coreDataManager.

Riferimenti



L'M in MVC è per "Modello" e nel paradigma MVC il ruolo delle classi modello è quello di gestire i dati di un programma. Un modello è l'opposto di una vista: una vista sa come visualizzare i dati, ma non sa nulla su cosa fare con i dati, mentre un modello sa tutto su come lavorare con i dati, ma nulla su come visualizzarli. I modelli possono essere complicati, ma non devono esserlo: il modello per la tua app potrebbe essere semplice come una serie di stringhe o dizionari.

Il ruolo di un controller è di mediare tra vista e modello. Pertanto, hanno bisogno di un riferimento a uno o più oggetti vista e uno o più oggetti modello. Diciamo che il tuo modello è una matrice di dizionari, con ogni dizionario che rappresenta una riga nella tua tabella. La vista root della tua app visualizza quella tabella e potrebbe essere responsabile del caricamento dell'array da un file. Quando l'utente decide di aggiungere una nuova riga alla tabella, tocca un pulsante e il controller crea un nuovo dizionario (modificabile) e lo aggiunge all'array. Per riempire la riga, il controller crea un controller della vista dettagli e gli assegna il nuovo dizionario. Il controller della vista dettagli riempie il dizionario e restituisce. Il dizionario è già parte del modello, quindi non deve succedere nient'altro.


Questa domanda sembra essere molto popolare qui su quindi ho pensato di provare a dare una risposta migliore per aiutare le persone che iniziano nel mondo di iOS come me.

Spero che questa risposta sia abbastanza chiara da far capire alla gente e che non mi sia sfuggito nulla.

Passare i dati in avanti

Trasmissione dei dati a un controller di visualizzazione da un altro controller di visualizzazione. Si utilizzerà questo metodo se si desidera passare un oggetto / valore da un controller di visualizzazione a un altro controller di visualizzazione che si sta spingendo su uno stack di navigazione.

Per questo esempio avremo ViewControllerA e ViewControllerB

Per passare un valore BOOL da ViewControllerA a ViewControllerB faremmo quanto segue.

  1. in ViewControllerB.h creare una proprietà per BOOL

    @property (nonatomic, assign) BOOL isSomethingEnabled;
    
  2. in ViewControllerA devi dirlo su ViewControllerB quindi usa un

    #import "ViewControllerB.h"
    

    Poi dove vuoi caricare la vista es. didSelectRowAtIndex o qualche IBAction è necessario impostare la proprietà in ViewControllerB prima di spingerlo nello stack nav.

    ViewControllerB *viewControllerB = [[ViewControllerB alloc] initWithNib:@"ViewControllerB" bundle:nil];
    viewControllerB.isSomethingEnabled = YES;
    [self pushViewController:viewControllerB animated:YES];
    

    Questo imposterà isSomethingEnabled in isSomethingEnabled al valore BOOL YES .

Passare i dati in avanti usando Segues

Se stai usando Storyboard, molto probabilmente stai usando segues e avrai bisogno di questa procedura per passare i dati in avanti. Questo è simile al precedente ma invece di passare i dati prima di premere il controller della vista, si usa un metodo chiamato

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender

Quindi per passare un BOOL da ViewControllerA a ViewControllerB faremmo quanto segue:

  1. in ViewControllerB.h creare una proprietà per BOOL

    @property (nonatomic, assign) BOOL isSomethingEnabled;
    
  2. in ViewControllerA devi dirlo su ViewControllerB quindi usa un

    #import "ViewControllerB.h"
    
  3. Crea un seguito da ViewControllerA a ViewControllerB sullo storyboard e "showDetailSegue" un identificatore, in questo esempio lo chiameremo "showDetailSegue"

  4. Quindi è necessario aggiungere il metodo a ViewControllerA che viene chiamato quando viene eseguito un qualsiasi passaggio, per questo è necessario rilevare quali passaggi sono stati chiamati e quindi fare qualcosa. Nel nostro esempio controlleremo "showDetailSegue" e se ciò viene eseguito passeremo il nostro valore BOOL a ViewControllerB

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

    Se le tue viste sono incorporate in un controller di navigazione, devi modificare leggermente il metodo in seguito

    -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
        if([segue.identifier isEqualToString:@"showDetailSegue"]){
            UINavigationController *navController = (UINavigationController *)segue.destinationViewController;
            ViewControllerB *controller = (ViewControllerB *)navController.topViewController;
            controller.isSomethingEnabled = YES;
        }
    }
    

    Questo imposterà isSomethingEnabled in isSomethingEnabled al valore BOOL YES .

Passare i dati indietro

Per passare i dati da ViewControllerB a ViewControllerA è necessario utilizzare protocolli e delegati o blocchi , quest'ultimo può essere utilizzato come meccanismo liberamente accoppiato per i callback.

Per fare ciò renderemo ViewControllerA un delegato di ViewControllerB . Ciò consente a ViewControllerB di inviare un messaggio a ViewControllerA permettendoci di inviare dati indietro.

Per ViewControllerA essere delegato di ViewControllerB deve essere conforme al protocollo ViewControllerB che dobbiamo specificare. Questo dice a ViewControllerA quali metodi deve implementare.

  1. In ViewControllerB.h , sotto #import , ma sopra @interface si specifica il protocollo.

    @class ViewControllerB;
    
    @protocol ViewControllerBDelegate <NSObject>
    - (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item;
    @end
    
  2. successivo ancora in ViewControllerB.h è necessario impostare una proprietà delegate e sintetizzare in ViewControllerB.m

    @property (nonatomic, weak) id <ViewControllerBDelegate> delegate;
    
  3. In ViewControllerB chiamiamo un messaggio sul delegate quando apriamo il controller della vista.

    NSString *itemToPassBack = @"Pass this value back to ViewControllerA";
    [self.delegate addItemViewController:self didFinishEnteringItem:itemToPassBack];
    
  4. Questo è tutto per ViewControllerB . Ora in ViewControllerA.h , dire a ViewControllerA di importare ViewControllerB e conformarsi al suo protocollo.

    #import "ViewControllerB.h"
    
    @interface ViewControllerA : UIViewController <ViewControllerBDelegate>
    
  5. In ViewControllerA.m implementare il seguente metodo dal nostro protocollo

    - (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item
    {
        NSLog(@"This was returned from ViewControllerB %@",item);
    }
    
  6. Prima di spingere viewControllerB nello stack di navigazione dobbiamo dire a ViewControllerB che ViewControllerA è il suo delegato, altrimenti avremo un errore.

    ViewControllerB *viewControllerB = [[ViewControllerB alloc] initWithNib:@"ViewControllerB" bundle:nil];
    viewControllerB.delegate = self
    [[self navigationController] pushViewController:viewControllerB animated:YES];
    

Riferimenti

  1. Utilizzo della delega per comunicare con altri controller di visualizzazione nella Guida alla programmazione del controller di visualizzazione
  2. Delegate Pattern

NSNotification center È un altro modo per passare i dati.

// add observer in controller(s) where you want to receive data
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleDeepLinking:) name:@"handleDeepLinking" object:nil];

-(void) handleDeepLinking:(NSNotification *) notification {
    id someObject = notification.object // some custom object that was passed with notification fire.
}

// post notification
id someObject;
[NSNotificationCenter.defaultCenter postNotificationName:@"handleDeepLinking" object:someObject];

Passaggio di dati da una classe all'altra (una classe può essere qualsiasi controller, gestore di rete / sessione, sottoclasse UIView o qualsiasi altra classe)

I blocchi sono funzioni anonime.

Questo esempio passa i dati dal controller B al controller A

definire un blocco

@property void(^selectedVoucherBlock)(NSString *); // in ContollerA.h

aggiungi gestore di blocchi (listener) dove hai bisogno di valore (ad esempio, hai bisogno della tua risposta API in ControllerA o hai bisogno dei dati ContorllerB su A)

// in ContollerA.m

- (void)viewDidLoad {
    [super viewDidLoad];
    __unsafe_unretained typeof(self) weakSelf = self;
    self.selectedVoucherBlock = ^(NSString *voucher) {
        weakSelf->someLabel.text = voucher;
    };
}

Vai al controller B

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
ControllerB *vc = [storyboard instantiateViewControllerWithIdentifier:@"ControllerB"];
vc.sourceVC = self;
    [self.navigationController pushViewController:vc animated:NO];

blocco di fuoco

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath: 
(NSIndexPath *)indexPath {
    NSString *voucher = vouchersArray[indexPath.row];
    if (sourceVC.selectVoucherBlock) {
        sourceVC.selectVoucherBlock(voucher);
    }
    [self.navigationController popToViewController:sourceVC animated:YES];
}

Un altro esempio di lavoro per i blocchi


Trovo la versione più semplice ed elegante con blocchi di passaggio. Diamo un nome al controller della vista che aspetta i dati restituiti come "A" e restituisce il controller della vista come "B". In questo esempio vogliamo ottenere 2 valori: il primo di Tipo1 e il secondo di Tipo2.

Supponendo che usiamo Storyboard, il primo controller imposta il blocco di callback, ad esempio durante la preparazione del seguito:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.destinationViewController isKindOfClass:[BViewController class]])
    {
        BViewController *viewController = segue.destinationViewController;

        viewController.callback = ^(Type1 *value1, Type2 *value2) {
            // optionally, close B
            //[self.navigationController popViewControllerAnimated:YES];

            // let's do some action after with returned values
            action1(value1);
            action2(value2);
        };

    }
}

e il controller di vista "B" dovrebbe dichiarare la proprietà callback, BViewController.h:

// it is important to use "copy"
@property (copy) void(^callback)(Type1 *value1, Type2 *value2);

Che nel file di implementazione BViewController.m dopo aver desiderato valori per restituire la nostra callback dovrebbe essere chiamato:

if (self.callback)
    self.callback(value1, value2);

Una cosa da ricordare è che l'uso del blocco spesso ha bisogno di gestire riferimenti forti e __weak come spiegato here


NewsViewController

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
  [tbl_View deselectRowAtIndexPath:indexPath animated:YES];
  News *newsObj = [newstitleArr objectAtIndex:indexPath.row];
  NewsDetailViewController *newsDetailView = [[NewsDetailViewController alloc] initWithNibName:@"NewsDetailViewController" bundle:nil];

  newsDetailView.newsHeadlineStr = newsObj.newsHeadline;

  [self.navigationController pushViewController:newsDetailView animated:YES];
}

NewsDetailViewController.h

@interface NewsDetailViewController : UIViewController
@property(nonatomic,retain) NSString *newsHeadlineStr;
@end

NewsDetailViewController.m

@synthesize newsHeadlineStr;

Passaggio dei dati tra FirstViewController a SecondViewController come di seguito

Per esempio:

FirstViewController String value as

StrFirstValue = @"first";

quindi possiamo passare questo valore in seconda classe usando il passaggio successivo

1> È necessario crare l'oggetto stringa nel file SecondViewController.h

NSString *strValue;

2> È necessario dichiarare la proprietà come sotto la dichiarazione sottostante nel file .h.

@property (strong, nonatomic)  NSString *strSecondValue;

3> È necessario sintetizzare tale valore nel file FirstViewController.m sotto la dichiarazione dell'intestazione

@synthesize strValue;

e in FirstViewController.h:

@property (strong, nonatomic)  NSString *strValue;

4> In FirstViewController, da quale metodo navighiamo in seconda vista, scrivi sotto il codice in quel metodo.

SecondViewController *secondView= [[SecondViewController alloc]     
initWithNibName:@"SecondViewController " bundle:[NSBundle MainBundle]];

[secondView setStrSecondValue:StrFirstValue];

[self.navigationController pushViewController:secondView animated:YES ];

Ci sono molte risposte a queste domande che offrono molti modi diversi per eseguire la comunicazione del controller di visualizzazione che funzionerebbe davvero, ma non vedo da nessuna parte che quale sia effettivamente la migliore da usare e quali evitare.

In pratica, a mio parere sono raccomandate solo poche soluzioni:

  • Per trasmettere i dati in avanti:
    • sovrascrivi il prepare(for:sender:)metodo di UIViewControllerquando usi uno storyboard e segue
    • passare i dati attraverso un inizializzatore o attraverso le proprietà quando si eseguono le transizioni del controller di vista attraverso il codice
  • Per passare i dati indietro
    • aggiorna lo stato condiviso dell'app (che puoi inoltrare tra i controller della vista con uno dei metodi precedenti)
    • utilizzare la delega
    • usa un seguito di svolgimento

Soluzioni Raccomando di NON usare:

  • Fare riferimento al controller precedente direttamente anziché utilizzare la delega
  • Condivisione dei dati tramite un singleton
  • Trasmissione dei dati tramite il delegato dell'app
  • Condivisione dei dati tramite le impostazioni predefinite dell'utente
  • Trasmissione dei dati tramite notifiche

Queste soluzioni, sebbene funzionino a breve termine, introducono troppe dipendenze che possono alterare l'architettura dell'app e creare più problemi in seguito.

Per quelli interessati, ho scritto alcuni articoli che affrontano questi punti in modo più approfondito e evidenziano i vari inconvenienti:


Esistono diversi metodi per la condivisione dei dati.

  1. Puoi sempre condividere i dati usando NSUserDefaults. Impostare il valore che si desidera condividere rispetto a una chiave di propria scelta e ottenere il valore da NSUserDefaultassociato a quel tasto nel controller della vista successivo.

    [[NSUserDefaults standardUserDefaults] setValue:value forKey:key]
    [[NSUserDefaults standardUserDefaults] objectForKey:key]
    
  2. Si può solo creare una proprietà in viewcontrollerA. Crea un oggetto di viewcontrollerAin viewcontrollerBe assegna il valore desiderato a quella proprietà.

  3. È inoltre possibile creare delegati personalizzati per questo.


Mi piace l'idea degli oggetti Model e degli oggetti Mock basati su NSProxy per salvare o scartare i dati se ciò che l'utente seleziona può essere cancellato.

È facile passare i dati in giro dato che si tratta di un singolo oggetto o di una coppia di oggetti e se si ha il controllo di UINavigationController, è possibile mantenere il riferimento all'interno del modello e tutti i controller di visualizzazione pushed possono accedervi direttamente dal controller di navigazione.


Non è questo il modo per farlo, dovresti usare delegati, suppongo che abbiamo due controller ViewController1 e ViewController2 e questo check è nel primo e quando il suo stato cambia, vuoi fare qualcosa in ViewController2, realizzalo nel modo giusto, dovresti fare quanto segue:

Aggiungi un nuovo file al tuo progetto (Protocollo Objective-C) File -> Nuovo, ora assegna il nome ViewController1Delegate o quello che vuoi e scrivilo tra le direttive @interface e @end

@optional

- (void)checkStateDidChange:(BOOL)checked;

Ora vai su ViewController2.h e aggiungi

#import "ViewController1Delegate.h"

quindi cambia la sua definizione in

@interface ViewController2: UIViewController<ViewController1Delegate>

Ora vai su ViewController2.m e all'interno dell'implementazione aggiungi:

- (void)checkStateDidChange:(BOOL)checked {
     if (checked) {
           // Do whatever you want here
           NSLog(@"Checked");
     }
     else {
           // Also do whatever you want here
           NSLog(@"Not checked");
     }
}

Ora vai su ViewController1.h e aggiungi la seguente proprietà:

@property (weak, nonatomic) id<ViewController1Delegate> delegate; 

Ora se stai creando ViewController1 all'interno di ViewController2 dopo qualche evento, allora dovresti farlo in questo modo usando i file NIB:

ViewController1* controller = [[NSBundle mainBundle] loadNibNamed:@"ViewController1" owner:self options:nil][0];
controller.delegate = self;
[self presentViewController:controller animated:YES completion:nil];

Ora sei tutto pronto, ogni volta che rilevi l'evento di controllo modificato in ViewController1, tutto ciò che devi fare è il seguente

[delegate checkStateDidChange:checked]; // You pass here YES or NO based on the check state of your control

Per favore dimmi se c'è qualcosa che non è chiaro se non ho capito bene la tua domanda.


Se vuoi inviare dati da uno a un altro viewController, ecco un modo per farlo:

Supponiamo di avere viewController: ViewController e NewViewController.

in ViewController.h

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController
{
    IBOutlet UITextField *mytext1,*mytext2,*mytext3,*mytext4;
}

@property (nonatomic,retain) IBOutlet UITextField *mytext1,*mytext2,*mytext3,*mytext4;

-(IBAction)goToNextScreen:(id)sender;

@end

in ViewController.m

#import "ViewController.h"

#import "NewViewController.h"

@implementation ViewController
@synthesize mytext1,mytext2,mytext3,mytext4;

-(IBAction)goToNextScreen:(id)sender
{
    NSArray *arr = [NSArray arrayWithObjects:mytext1.text,mytext2.text,mytext3.text,mytext4.text, nil];


    NewViewController *newVc = [[NewViewController alloc] initWithNibName:@"NewViewController" bundle:nil];

    newVc.arrayList = arr;

    [self.navigationController pushViewController:newVc animated:YES];

}

In NewViewController.h

#import <UIKit/UIKit.h>

@interface NewViewController : UITableViewController
{
    NSArray *arrayList;

    NSString *name,*age,*dob,*mobile;

}

@property(nonatomic, retain)NSArray *arrayList;

@end

In NewViewController.m

#import "NewViewController.h"

#import "ViewController.h"

@implementation NewViewController
@synthesize arrayList;

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{

    // Return the number of sections.
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{

    // Return the number of rows in the section.
    return [arrayList count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil)
    {
         cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];      
    }
    // Configure the cell...
    cell.textLabel.text = [arrayList objectAtIndex:indexPath.row];
    return cell;


}

@end

In questo modo possiamo passare i dati da un viewcontroller a un altro controller di visualizzazione ...


Se vuoi inviare dati da uno a un altro viewController, ecco un modo per farlo:

Supponiamo di avere viewController: viewControllerA e viewControllerB

Ora in viewControllerB.h

@interface viewControllerB : UIViewController {

  NSString *string;
  NSArray *array;

}

- (id)initWithArray:(NSArray)a andString:(NSString)s;

In viewControllerB.m

#import "viewControllerB.h"

@implementation viewControllerB

- (id)initWithArray:(NSArray)a andString:(NSString)s {

   array = [[NSArray alloc] init];
   array = a;

   string = [[NSString alloc] init];
   string = s;

}

In viewControllerA.m

#import "viewControllerA.h"
#import "viewControllerB.h"

@implementation viewControllerA

- (void)someMethod {

  someArray = [NSArray arrayWithObjects:@"One", @"Two", @"Three", nil];
  someString = [NSString stringWithFormat:@"Hahahahaha"];

  viewControllerB *vc = [[viewControllerB alloc] initWithArray:someArray andString:someString];

  [self.navigationController pushViewController:vc animated:YES];
  [vc release];

}

Ecco come è possibile passare i dati da viewControllerA a viewControllerB senza impostare alcun delegato. ;)


se vuoi passare i dati da ViewControlerOne a ViewControllerTwo prova questi ..

fare questi in ViewControlerOne.h

 @property (nonatomic, strong) NSString *str1;

fare questi in ViewControllerTwo.h

 @property (nonatomic, strong) NSString *str2;

Sintetizzare str2 in ViewControllerTwo.m

@interface ViewControllerTwo ()
@end
@implementation ViewControllerTwo
@synthesize str2;

fare questi in ViewControlerOne.m

 - (void)viewDidLoad
 {
   [super viewDidLoad];

  // Data or string you wants to pass in ViewControllerTwo..
  self.str1 = @"hello world";

 }

sui pulsanti clicca evento fai questo ..

-(IBAction)ButtonClicked
{ //Navigation on buttons click event from ViewControlerOne to ViewControlerTwo with transferring data or string..
  ViewControllerTwo *objViewTwo=[self.storyboard instantiateViewControllerWithIdentifier:@"ViewControllerTwo"];
  obj.str2=str1;
  [self.navigationController pushViewController: objViewTwo animated:YES];
}

fare questi in ViewControllerTwo.m

- (void)viewDidLoad
{
 [super viewDidLoad];
  NSLog(@"%@",str2);
}

È possibile salvare i dati nel delegato App per accedervi attraverso i controller di visualizzazione nella propria applicazione. Tutto ciò che devi fare è creare un'istanza condivisa di delegato dell'app

AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;

Per esempio

se si dichiara un, NSArray object *arrayXYZallora è possibile accedervi da qualsiasi controller di vistaappDelegate.arrayXYZ


Crea la proprietà al prossimo view controller .he definisci getter e setter.

Aggiungi questo propertyin NextVC.h su nextVC

@property (strong, nonatomic) NSString *indexNumber;

Inserisci

@synthesize indexNumber; in NextVC.m

E ultimo

NextVC *vc=[[NextVC alloc]init];

[email protected]"123";

[self.navigationController vc animated:YES];

Ho visto un sacco di persone a complicare questo usando il didSelectRowAtPathmetodo. Sto usando Core Data nel mio esempio.

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{

    //this solution is for using Core Data
    YourCDEntityName * value = (YourCDEntityName *)[[self fetchedResultsController] objectAtIndexPath: indexPath];

    YourSecondViewController * details = [self.storyboard instantiateViewControllerWithIdentifier:@"nameOfYourSecondVC"];//make sure in storyboards you give your second VC an identifier

    //Make sure you declare your value in the second view controller
    details.selectedValue = value;

    //Now that you have said to pass value all you need to do is change views
    [self.navigationController pushViewController: details animated:YES];

}

4 linee di codice all'interno del metodo e il gioco è fatto.


Nel mio caso ho usato una classe singleton che può funzionare come un oggetto globale che consente l'accesso ai dati da quasi ovunque nell'app. La prima cosa è costruire una classe singleton. Si prega di fare riferimento alla pagina, " Come dovrebbe apparire il mio singleton Objective-C? " E quello che ho fatto per rendere l'oggetto globalmente accessibile è stato semplicemente importarlo in appName_Prefix.pchcui è possibile applicare l'istruzione import in ogni classe. Per accedere a questo oggetto e usarlo, ho semplicemente implementato il metodo di classe per restituire l'istanza condivisa, che contiene le sue variabili


Questo è un tutorial davvero eccezionale per chiunque ne voglia uno. Ecco il codice di esempio:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if ([segue.identifier isEqualToString:@"myIdentifer]) {
        NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
        myViewController *destViewController = segue.destinationViewController;
        destViewController.name = [object objectAtIndex:indexPath.row];
    }
}




uiviewcontroller