Transmission de données entre les contrôleurs de vue
je suis nouveau à iOS et Objective-C et l'ensemble du paradigme MVC et je suis coincé avec ce qui suit:
j'ai une vision qui agit comme un formulaire de saisie de données et je veux donner à l'utilisateur la possibilité de sélectionner plusieurs produits. Les produits sont listés sur une autre vue avec un UITableViewController
et j'ai activé plusieurs sélections.
Ma question est, comment puis-je transférer les données d'une vue à l'autre? Je tiendrai les sélections sur le UITableView
dans un tableau, mais comment puis-je transmettre que de nouveau à la vue de formulaire de saisie de données précédente de sorte qu'il peut être sauvé avec les autres données aux données de base lors de la soumission du formulaire?
j'ai surfé et vu des gens déclarer un tableau dans l'app delegate. J'ai lu quelque chose sur les Singletons mais je ne comprends pas ce que c'est et j'ai lu quelque chose sur la création d'un modèle de données.
quelle serait la bonne façon d'effectuer ceci et comment ferais-je il?
30 réponses
cette question semble être très populaire ici sur stackoverflow donc j'ai pensé que je voudrais essayer et donner une meilleure réponse pour aider les gens qui commencent dans le monde de iOS comme moi.
j'espère que cette réponse est assez claire pour que les gens comprennent que je n'ai pas manqué de rien.
Transmission De Données
transfert de données vers un contrôleur de vue à partir d'un autre contrôleur de vue. Vous utilisez cette méthode si vous voulez passer un objet/valeur d'un contrôleur de vue à un autre contrôleur de vue que vous pouvez pousser sur une pile de navigation.
pour cet exemple nous aurons ViewControllerA
et ViewControllerB
pour passer une valeur BOOL
de ViewControllerA
à ViewControllerB
nous ferions ce qui suit.
-
dans
ViewControllerB.h
créer une propriété pour laBOOL
@property (nonatomic, assign) BOOL isSomethingEnabled;
-
dans
ViewControllerA
vous avez besoin de le dire au sujetViewControllerB
donc utiliser un#import "ViewControllerB.h"
Ensuite où vous voulez charger la vue par exemple.
didSelectRowAtIndex
ou d'unIBAction
vous devez définir la propriétéViewControllerB
avant d'appuyer sur nav pile.ViewControllerB *viewControllerB = [[ViewControllerB alloc] initWithNib:@"ViewControllerB" bundle:nil]; viewControllerB.isSomethingEnabled = YES; [self pushViewController:viewControllerB animated:YES];
ce paramètre définit
isSomethingEnabled
dansViewControllerB
àBOOL
valeurYES
.
transmettre des données en utilisant les segments
si vous utilisez des Storyboards, vous utilisez très probablement des segments et vous aurez besoin de cette procédure pour transmettre les données vers l'avant. Ceci est similaire à ce qui précède mais au lieu de passer les données avant de pousser le contrôleur de vue, vous utilisez une méthode appelée
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
donc pour passer un BOOL
de ViewControllerA
à ViewControllerB
nous ferions le
-
dans
ViewControllerB.h
créer une propriété pour laBOOL
@property (nonatomic, assign) BOOL isSomethingEnabled;
-
dans
ViewControllerA
vous avez besoin de le dire au sujetViewControllerB
donc utiliser un#import "ViewControllerB.h"
-
créer une transition de
ViewControllerA
àViewControllerB
sur le storyboard et lui donner un identifiant, dans cet exemple nous l'appellerons"showDetailSegue"
-
ensuite, nous devons ajouter la méthode à
ViewControllerA
qui s'appelle lorsque n'importe quelle séquence est effectuée, pour cette raison, nous devons détecter quelle séquence a été appelée et puis faire quelque chose. Dans notre exemple, nous allons vérifier pour"showDetailSegue"
et si cela est effectué, nous passerons notreBOOL
valeur àViewControllerB
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{ if([segue.identifier isEqualToString:@"showDetailSegue"]){ ViewControllerB *controller = (ViewControllerB *)segue.destinationViewController; controller.isSomethingEnabled = YES; } }
si vous avez vos vues intégrées dans un contrôleur de navigation, vous devez modifier légèrement la méthode ci-dessus après
-(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; } }
ce paramètre définit
isSomethingEnabled
dansViewControllerB
àBOOL
valeurYES
.
Transmission De Données
pour transmettre les données de ViewControllerB
à ViewControllerA
vous devez utiliser protocoles et délégués ou blocs , ce dernier peut être utilisé comme un mécanisme à couplage lâche pour rappel.
pour ce faire, nous ferons de ViewControllerA
un délégué de ViewControllerB
. Cela permet à ViewControllerB
d'envoyer un message de retour à ViewControllerA
nous permettant de renvoyer des données.
pour ViewControllerA
pour être délégué de ViewControllerB
il doit être conforme au Protocole de ViewControllerB
que nous devons spécifier. Cela indique ViewControllerA
quelles méthodes il doit mettre en œuvre.
-
Dans
ViewControllerB.h
, au-dessous du#import
, mais au-dessus du@interface
vous spécifiez le protocole.@class ViewControllerB; @protocol ViewControllerBDelegate <NSObject> - (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item; @end
-
prochaine encore dans le
ViewControllerB.h
vous devez configurer undelegate
de la propriété et de synthétiser dansViewControllerB.m
@property (nonatomic, weak) id <ViewControllerBDelegate> delegate;
-
Dans
ViewControllerB
nous appelons un message sur ledelegate
lorsque nous de la pop la-vue-contrôleur.NSString *itemToPassBack = @"Pass this value back to ViewControllerA"; [self.delegate addItemViewController:self didFinishEnteringItem:itemToPassBack];
-
c'est ça pour
ViewControllerB
. Maintenant dansViewControllerA.h
, direViewControllerA
pour importerViewControllerB
et se conformer à son protocole.#import "ViewControllerB.h" @interface ViewControllerA : UIViewController <ViewControllerBDelegate>
-
Dans
ViewControllerA.m
mettre en œuvre la méthode suivante de notre protocole- (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item { NSLog(@"This was returned from ViewControllerB %@",item); }
-
avant de pousser
viewControllerB
à la pile de navigation nous devons direViewControllerB
queViewControllerA
est son délégué, sinon nous obtiendrons une erreur.ViewControllerB *viewControllerB = [[ViewControllerB alloc] initWithNib:@"ViewControllerB" bundle:nil]; viewControllerB.delegate = self [[self navigationController] pushViewController:viewControllerB animated:YES];
références
- utilisation de la Délégation pour communiquer avec D'autres contrôleurs de vue dans le Guide de programmation du contrôleur de vue
- Modèle De Délégué
Swift
Il ya des tonnes et des tonnes d'explications ici et autour de StackOverflow, mais si vous êtes un débutant juste essayer d'obtenir quelque chose de base à travailler, essayer de regarder ce tutoriel YouTube (C'est ce qui m'a aidé à enfin comprendre comment le faire).
- YouTube tutoriel: Comment envoyer des données à travers des enchaînements (swift)
transmettre des données vers la vue suivante Contrôleur
ce qui suit est un exemple basé sur la vidéo. L'idée est de passer une chaîne du champ texte dans le Controller de la première vue au label dans le Controller de la deuxième vue.
créer la disposition du storyboard dans le constructeur de L'Interface. Pour faire la séquence, vous juste contrôle cliquez sur le bouton et faites glisser vers la deuxième vue Contrôleur.
Premier-Vue-Contrôleur
le code pour le contrôleur de première vue est
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!
}
}
Seconde Vue-Contrôleur
et le code pour le contrôleur de deuxième vue est
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
}
}
N'oubliez pas
- raccorder les prises de la
UITextField
et leUILabel
. - définit les contrôleurs first et second View aux fichiers Swift appropriés dans IB.
Passage des données en arrière-Vue-Contrôleur
pour renvoyer les données du contrôleur de deuxième vue au contrôleur de première vue, vous utilisez un protocole et un délégué . Cette vidéo est cependant une marche très claire de ce processus:
- tutorial YouTube: Tutorial iOS Swift Basics: protocoles et délégués mais aussi lire ce post pour s'assurer que vous n'entrez pas dans un cycle de référence fort.
ce qui suit est un exemple basé sur la vidéo (avec quelques modifications).
créer la disposition du storyboard dans l'Interface Constructeur. Encore une fois, pour faire la séquence, vous juste contrôle glisser du bouton au contrôleur de deuxième vue. Définissez l'identifiant de segue à showSecondViewController
. Aussi, n'oubliez pas de raccorder les prises et les actions en utilisant les noms dans le code suivant.
Premier-Vue-Contrôleur
le code pour le contrôleur de première vue est
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
}
}
notez l'utilisation de notre coutume DataEnteredDelegate
protocole.
Seconde Vue-Contrôleur et le Protocole
le code pour le contrôleur de deuxième vue est
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)
}
}
noter que le protocol
est en dehors de la classe de contrôleur de vue.
C'est ça. En lançant l'application maintenant, vous devriez être en mesure de renvoyer des données du contrôleur de la deuxième vue vers le premier.
le M dans MVC est pour" Modèle " et dans le paradigme MVC le rôle des classes de modèle est de gérer les données d'un programme. Un modèle est à l'opposé de vue -- une vue sait comment afficher les données, mais il ne sait rien à propos de quoi faire avec les données, alors qu'un modèle sait tout sur comment travailler avec les données, mais rien sur la façon de l'afficher. Les modèles peuvent être compliqués, mais ils n'ont pas à l'être -- le modèle de votre application peut être aussi simple qu'un tableau de chaînes ou de dictionnaires.
le rôle d'un contrôleur est de servir de médiateur entre la vue et le modèle. Par conséquent, ils ont besoin d'une référence à un ou plusieurs objets view et un ou plusieurs objets model. Disons que votre modèle est un tableau de dictionnaires, chaque dictionnaire représentant une rangée dans votre table. La vue racine de votre application affiche cette table, et elle pourrait être responsable du chargement du tableau à partir d'un fichier. Lorsque l'utilisateur décide d'ajouter une nouvelle ligne à la table, ils appuyez sur quelques boutons et votre contrôleur crée un nouveau (mutable) dictionnaire et l'ajoute au tableau. Afin de remplir la ligne, Le contrôleur crée un contrôleur de vue de détail et lui donne le nouveau dictionnaire. Le contrôleur de vue de détail remplit le dictionnaire et retourne. Le dictionnaire fait déjà partie du modèle, donc rien d'autre ne doit se produire.
il existe différentes façons de recevoir une donnée à une classe différente dans iOS. Par exemple -
- initialisation directe après l'attribution d'une autre classe.
- Délégation - de la transmission des données en arrière
- de Notification pour la diffusion de données à de multiples classes en une seule fois
- sauver dans
NSUserDefaults
- pour y accéder plus tard - Singleton classes
- bases de données et autres mécanismes de stockage comme plist, etc.
sans le scénario simple de la transmission d'une valeur à une classe différente dont l'attribution est faite dans la classe courante, la méthode la plus courante et préférée serait le réglage direct des valeurs après l'attribution. Ceci est fait comme suit:-
nous pouvons le comprendre en utilisant deux contrôleurs - Controller1 et Controller2
supposons que dans la classe Controller1 vous voulez créer L'objet Controller2 et le pousser avec une chaîne de valeur passée. Ceci peut être fait comme ceci: -
- (void)pushToController2 {
Controller2 *obj = [[Controller2 alloc] initWithNib:@"Controller2" bundle:nil];
[obj passValue:@"String"];
[self pushViewController:obj animated:YES];
}
dans la mise en œuvre de la classe Controller2 il y aura cette fonction comme -
@interface Controller2 : NSObject
@property (nonatomic , strong) NSString* stringPassed;
@end
@implementation Controller2
@synthesize stringPassed = _stringPassed;
- (void) passValue:(NSString *)value {
_stringPassed = value; //or self.stringPassed = value
}
@end
vous pouvez également définir directement les propriétés de la classe Controller2 de la même manière que ceci:
- (void)pushToController2 {
Controller2 *obj = [[Controller2 alloc] initWithNib:@"Controller2" bundle:nil];
[obj setStringPassed:@"String"];
[self pushViewController:obj animated:YES];
}
Pour passer plusieurs valeurs peut utiliser les paramètres multiples comme: -
Controller2 *obj = [[Controller2 alloc] initWithNib:@"Controller2" bundle:nil];
[obj passValue:@“String1” andValues:objArray withDate:date];
ou si vous avez besoin de passer plus de 3 paramètres qui sont liés à une caractéristique commune, vous pouvez stocker les valeurs à une classe de Modèle et passer ce modelObject à la classe suivante
ModelClass *modelObject = [[ModelClass alloc] init];
modelObject.property1 = _property1;
modelObject.property2 = _property2;
modelObject.property3 = _property3;
Controller2 *obj = [[Controller2 alloc] initWithNib:@"Controller2" bundle:nil];
[obj passmodel: modelObject];
Donc en bref si vous voulez - des
1) set the private variables of the second class initialise the values by calling a custom function and passing the values.
2) setProperties do it by directlyInitialising it using the setter method.
3) pass more that 3-4 values related to each other in some manner , then create a model class and set values to its object and pass the object using any of the above process.
Espérons que cette aide
après plus de recherche, il a semblé que les protocoles et les délégués est la bonne façon/Apple préféré de le faire.
j'ai fini par utiliser cet exemple
partage de données entre les contrôleurs de vue et d'autres objets @ iPhone Dev SDK
a bien fonctionné et m'a permis de passer une corde et un tableau en avant et en arrière entre mes vues.
Merci à tous pour votre aide
je trouve la version la plus simple et la plus élégante avec des blocs de passage. Nommons le contrôleur de vue qui attend les données retournées comme "A" et renvoie le contrôleur de vue comme "B". Dans cet exemple, nous voulons obtenir 2 valeurs: la première de Type1 et la seconde de Type2.
en supposant que nous utilisions Storyboard, le premier contrôleur définit le bloc de rappel, par exemple lors de la préparation de la séquence:
- (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);
};
}
}
Le contrôleur de vue et" B " devrait déclarer la propriété callback, BViewController.h:
// it is important to use "copy"
@property (copy) void(^callback)(Type1 *value1, Type2 *value2);
que dans le fichier d'implémentation BViewController.m après que nous avons des valeurs souhaitées pour retourner notre callback devrait être appelé:
if (self.callback)
self.callback(value1, value2);
une chose à se rappeler est que l'utilisation de bloc a souvent besoin de gérer des références fortes et _ _ faibles comme expliqué ici
il y a de bonnes informations dans plusieurs des réponses données, mais aucune ne répond entièrement à la question.
La question porte sur la transmission d'informations entre les contrôleurs de vue. L'exemple spécifique donné pose des questions sur la transmission de l'information entre les vues, mais compte tenu de la nouveauté auto-déclarée à iOS, l'affiche originale signifiait probablement entre les viewControllers, et non entre les vues (sans aucune intervention des ViewControllers). Il semble que toutes les réponses se concentrent sur deux vue des contrôleurs, mais que faire si l'application évolue à la nécessité d'impliquer plus de deux contrôleurs de vue de l'échange d'informations?
L'affiche originale a également demandé à propos de Singletons et l'utilisation de la AppDelegate . Ces questions doivent être répondues.
aider quiconque de regarder cette question, qui veut une réponse, je vais tenter de les fournir.
Scénarios D'Application
plutôt que d'avoir une discussion hautement hypothétique et abstraite, il est utile d'avoir des applications concrètes à l'esprit. Pour aider à définir une situation de contrôleur à deux vues et une situation de contrôleur à plus de deux vues, je vais définir deux scénarios d'application concrets.
scénario un: les contrôleurs de vue deux maximum ont besoin de partager des informations. Voir le schéma.
il y a deux contrôleurs de vue dans l'application. Il y a une ViewControllerA (formulaire de saisie de données), et un contrôleur de vue B (Liste de produits). Les éléments sélectionnés dans la liste de produit doivent correspondre aux éléments affichés dans la zone de texte dans le formulaire de saisie de données. Dans ce scénario, ViewControllerA et ViewControllerB doivent communiquer directement entre eux et aucun autre contrôleur de vue.
scénario deux : plus de deux contrôleurs besoin de partager les mêmes informations. Voir le schéma à deux.
il y a quatre contrôleurs de vue dans l'application. Il s'agit d'une application basée sur des onglets pour gérer l'inventaire à domicile. Trois contrôleurs de vue présentent différemment des vues filtrées des mêmes données:
- ViewControllerA-Articles De Luxe
- ViewControllerB-éléments Non assurés
- ViewControllerC-Total Home Inventory
- ViewControllerD - Ajouter Un Nouvel Élément De Formulaire
chaque fois qu'un élément individuel est créé ou édité, il doit également se synchroniser avec les autres contrôleurs de vue. Par exemple, si nous ajoutons un bateau dans ViewControllerD, mais il n'est pas encore assuré, alors le bateau doit apparaître lorsque l'utilisateur se rend à ViewControllerA (Articles de luxe), et aussi ViewControllerC( Inventaire maison entière), mais pas quand L'utilisateur va à ViewControllerB (articles non assurés). Nous devons nous préoccuper non seulement d'ajouter de nouveaux éléments, mais aussi de supprimer des éléments (ce qui peut être autorisé à partir de l'un des quatre contrôleurs de vue), ou d'éditer des éléments existants (ce qui peut être autorisé à partir de la "Add New Item Form", réaffectant la même chose pour l'édition).
puisque tous les contrôleurs de vue ont besoin de partager les mêmes données, les quatre contrôleurs de vue doivent rester en synchronisation, et donc il doit y avoir un certain sorte de communication à tous les autres contrôleurs de vue, chaque fois qu'un contrôleur de vue unique modifie les données sous-jacentes. Il devrait être assez évident que nous ne voulons pas que chaque contrôleur de vue communique directement avec l'autre contrôleur de vue dans ce scénario. Dans le cas où ce n'est pas évident, considérez si nous avions 20 contrôleurs de vue différents (plutôt que seulement 4). Comment difficile et sujette à erreur serait de s'informer sur les 19 autres contrôleurs de vue tout moment une vue contrôleur fait un changement?
Les Solutions: les Délégués et les Observateurs de Patron, et les Singletons
Dans le scénario, nous avons plusieurs solutions viables, comme d'autres réponses ont donné
- séquences
- délégués
- réglage direct des propriétés des contrôleurs de vue
- NSUserDefaults (en fait un mauvais choix)
Dans le deuxième scénario, nous avons d'autres solutions viables:
- Modèle Observateur
- Singletons
A singleton est une instance d'une classe, cette instance étant la seule instance en existence au cours de sa vie. Un singleton tire son nom du fait qu'elle est la seule instance. Normalement les développeurs qui utilisent des singletons ont des méthodes de classe spéciales pour y accéder.
+ (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;
}
maintenant que nous comprenons ce qu'est un singleton, discutons comment un singleton s'inscrit dans le schéma de l'observateur. Le motif de l'observateur est utilisé pour qu'un objet réponde aux changements par un autre objet. Dans le second scénario, nous avons quatre contrôleurs de vue différents, qui veulent tous être informés des changements apportés aux données sous-jacentes. Les "données sous-jacentes" doivent appartenir à une instance unique, un singleton. Le "savoir sur les changements" est accompli en observant les changements Singleton.
L'application d'inventaire domestique aurait une instance unique d'une classe qui est conçue pour gérer une liste d'articles d'inventaire. Le gestionnaire gérerait une collection d'articles ménagers. Voici une définition de classe pour le data manager:
#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
lorsque la collecte des articles d'inventaire à domicile change, les contrôleurs de vue doivent être informés de ce changement. La définition de classe ci-dessus ne rend pas évident comment cela va se passer. Nous devons suivre le modèle de l'observateur. Les contrôleurs de vue doivent observer formellement le sharedManager. Il y a deux façons d'observer un autre objet:
- Clé-Valeur d'Observation (KVO)
- NSNotificationCenter.
dans le deuxième scénario, nous n'avons pas une seule propriété du chef de ménage qui pourrait être observée en utilisant KVO. Parce que nous n'avons pas une seule propriété qui est facilement observable, le modèle de l'observateur, dans ce cas, doit être mis en œuvre en utilisant NSNotificationCenter. Chacun des quatre contrôleurs de vue souscrirait aux notifications, et le sharedManager enverrait les notifications au centre de notification le cas échéant. Le gestionnaire d'inventaire n'a pas besoin de savoir quoi que ce soit sur les contrôleurs de vue ou les instances d'autres classes qui peuvent être intéressés à savoir quand la collecte des articles d'inventaire change; le NSNotificationCenter s'occupe de ces détails de mise en œuvre. Les contrôleurs de vue s'abonnent simplement aux notifications, et le gestionnaire de données affiche simplement les notifications.
beaucoup de programmeurs débutants profitent du fait qu'il y a toujours exactement un "délégué D'Application 151980920" dans la durée de vie de l'application, qui est globalement accessible. Les programmeurs débutants utilisent ce fait pour bourrer des objets et des fonctionnalités dans l'appDelegate comme une commodité pour l'accès à partir de n'importe où ailleurs dans application. Ce n'est pas parce que L'AppDelegate est un singleton qu'il doit remplacer tous les autres Singleton. Il s'agit d'une mauvaise pratique, car elle impose un fardeau trop lourd à une classe, brisant les bonnes pratiques axées sur les objets. Chaque classe doit avoir un rôle clair qui s'explique facilement, souvent juste par le nom de la classe.
chaque fois que votre délégué D'Application commence à être gonflé, commencez à supprimer la fonctionnalité dans les singletons. Par exemple, la pile de données de base ne devrait pas être laissé dans L'AppDelegate, mais devrait plutôt être mis dans sa propre classe, une classe coreDataManager.
Références
il existe plusieurs méthodes pour partager les données.
-
vous pouvez toujours partager des données en utilisant
NSUserDefaults
. Définir la valeur que vous souhaitez partager à l'égard d'une clé de votre choix et obtenir la valeur deNSUserDefault
associée à cette clé dans la fenêtre contrôleur.[[NSUserDefaults standardUserDefaults] setValue:value forKey:key] [[NSUserDefaults standardUserDefaults] objectForKey:key]
-
vous pouvez créer une propriété dans
viewcontrollerA
. Créer un objet deviewcontrollerA
dansviewcontrollerB
et assigner la valeur désirée pour cette propriété. -
vous pouvez également créer des délégués personnalisés pour cela.
renvoyer des données de ViewController 2 (destination) à viewController 1(Source) est la chose la plus intéressante. En supposant que vous utilisez storyBoard ce sont toutes les façons que j'ai découvert:
- délégué
- Notification
- Utilisateur par défaut
- Singleton
ceux-ci ont déjà été discutés ici.
j'ai trouvé qu'il y a d'autres moyens:
- utilisant les callbacks de bloc:
utilisez-le dans la méthode prepareForSegue
dans la VC1
NextViewController *destinationVC = (NextViewController *) segue.destinationViewController;
[destinationVC setDidFinishUsingBlockCallback:^(NextViewController *destinationVC)
{
self.blockLabel.text = destination.blockTextField.text;
}];
- utilisant des story-boards déroulement (sortie)
implémenter une méthode avec un argument UIStoryboardSegue en VC 1, comme celui-ci:
-(IBAction)UnWindDone:(UIStoryboardSegue *)segue { }
dans le crochet du storyBoard le bouton "return" vers la sortie verte bouton (Unwind) de la CV. Maintenant, vous avez une "retour en arrière" afin que vous puissiez utiliser le destinationViewController propriété dans la prépareforsegue de VC2 et modifiez une propriété de VC1 avant qu'il remonte.
-
une autre option d'utiliser storyboards Undwind (Exit) - vous pouvez utilisez la méthode que vous avez écrite dans VC1
-(IBAction)UnWindDone:(UIStoryboardSegue *)segue { NextViewController *nextViewController = segue.sourceViewController; self.unwindLabel.text = nextViewController.unwindPropertyPass; }
et dans la rubrique "prepareForSegue of VC1" vous pouvez changer n'importe quel bien que vous voulez partager.
dans les deux décompressions options, vous pouvez définir la propriété tag de la touche et le prepareForSegue.
J'espère que j'ai ajouté quelque chose à la discussion.
:) Cheers.
L'OP n'a pas mentionné les contrôleurs de vue, mais tellement de réponses le font, que j'ai voulu intervenir avec ce que certaines des nouvelles fonctionnalités du LLVM permettent de rendre cela plus facile en voulant passer des données d'un contrôleur de vue à un autre et puis obtenir des résultats de retour.
story-board segues, ARC and LLVM blocks rendent cela plus facile que jamais pour moi. Certaines réponses ci-dessus mentionnaient déjà des scénarios et des séquences, mais s'appuyaient toujours sur la délégation. Définition des délégués fonctionne certes, mais certaines personnes peuvent trouver plus facile de passer des pointeurs ou des blocs de code.
avec UINavigators et segues, il y a des moyens faciles de transmettre l'information au contrôleur asservi et de récupérer l'information. ARC fait passer des pointeurs vers des choses dérivées de NSObjects simple ainsi si vous voulez le contrôleur subservient ajouter/modifier/modifier certaines données pour vous, passer un pointeur à une instance mutable. Les blocs rendent les actions de passage faciles Donc si vous voulez contrôleur asservi pour invoquer une action sur votre contrôleur supérieur, passez-lui un bloc. Vous définissez le bloc à accepter n'importe quel nombre d'arguments qui fait sens pour vous. Vous pouvez également concevoir L'API pour utiliser plusieurs blocs si cela vous convient mieux.
voici deux exemples triviaux de la colle. Le premier est simple montrant un paramètre passé pour l'entrée, le deuxième pour la sortie.
// Prepare the destination view controller by passing it the input we want it to work on
// and the results we will look at when the user has navigated back to this controller's view.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
[[segue destinationViewController]
// This parameter gives the next controller the data it works on.
segueHandoffWithInput:self.dataForNextController
// This parameter allows the next controller to pass back results
// by virtue of both controllers having a pointer to the same object.
andResults:self.resultsFromNextController];
}
ce second exemple montre passer un bloc de rappel pour le second argument. J'aime utiliser des blocs parce qu'il garde les détails pertinents étroitement ensemble dans la source - la source de niveau supérieur.
// Prepare the destination view controller by passing it the input we want it to work on
// and the callback when it has done its work.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
[[segue destinationViewController]
// This parameter gives the next controller the data it works on.
segueHandoffWithInput:self.dataForNextController
// This parameter allows the next controller to pass back results.
resultsBlock:^(id results) {
// This callback could be as involved as you like.
// It can use Grand Central Dispatch to have work done on another thread for example.
[self setResultsFromNextController:results];
}];
}
si vous voulez transmettre des données d'un contrôleur à un autre essayez ce code
premier ViewController.h
@property (nonatomic, retain) NSString *str;
SecondViewController.h
@property (nonatomic, retain) NSString *str1;
premier ViewController.m
- (void)viewDidLoad
{
// message for the second SecondViewController
self.str = @"text message";
[super viewDidLoad];
}
-(IBAction)ButtonClicked
{
SecondViewController *secondViewController = [[SecondViewController alloc] initWithNibName:@"SecondViewController" bundle:nil];
secondViewController.str1 = str;
[self.navigationController pushViewController:secondViewController animated:YES];
}
je cherchais cette solution depuis longtemps, au moins je l'ai trouvée. Tout d'abord, déclarez tous les objets de votre second ViewController.h de fichier comme
@interface SecondViewController: UIviewController
{
NSMutableArray *myAray;
CustomObject *object;
}
maintenant dans votre fichier de mise en œuvre allouer la mémoire pour ces objets comme ceci
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self)
{
// Custom initialization
myAray=[[NSMutableArray alloc] init];
object=[[CustomObject alloc] init];
}
return self;
}
Maintenant vous avez alloué la mémoire pour Array
et l'objet. maintenant vous pouvez remplir cette mémoire avant de pousser ce ViewController
SecondViewController.h et écrire deux méthodes
-(void)setMyArray:(NSArray *)_myArray;
-(void)setMyObject:(CustomObject *)_myObject;
dans le fichier d'implémentation vous pouvez implémenter la fonction
-(void)setMyArray:(NSArray *)_myArray
{
[myArra addObjectsFromArray:_myArray];
}
-(void)setMyObject:(CustomObject *)_myObject
{
[object setCustomObject:_myObject];
}
attendent que votre CustomObject
doit avoir une fonction de définition.
maintenant, votre travail de base est fait. allez à l'endroit où vous voulez pousser le SecondViewController
et faire les choses suivantes
SecondViewController *secondView= [[SecondViewController alloc] initWithNibName:@"SecondViewController " bundle:[NSBundle MainBundle]] ;
[secondView setMyArray:ArrayToPass];
[secondView setMyObject:objectToPass];
[self.navigationController pushViewController:secondView animated:YES ];
faites attention aux fautes d'orthographe.
ce n'est pas la façon de le faire, vous devriez utiliser des délégués, je suppose que nous avons deux contrôleurs de vue ViewController1 et ViewController2 et cette chose de contrôle est dans le PREMIER un et quand son état change, vous voulez faire quelque chose dans ViewController2, pour atteindre que de la bonne manière, vous devriez faire le ci-dessous:
ajoutez un nouveau fichier à votre fichier de projet (protocole objectif - c) - > Nouveau, nommez-le maintenant ViewController1Delegate ou ce que vous voulez et écrivez ces entre les directives @interface et @ end
@optional
- (void)checkStateDidChange:(BOOL)checked;
maintenant, allez sur ViewController2.h et ajouter
#import "ViewController1Delegate.h"
puis changer sa définition en
@interface ViewController2: UIViewController<ViewController1Delegate>
maintenant, allez sur ViewController2.m et à l'intérieur de la mise en œuvre ajouter:
- (void)checkStateDidChange:(BOOL)checked {
if (checked) {
// Do whatever you want here
NSLog(@"Checked");
}
else {
// Also do whatever you want here
NSLog(@"Not checked");
}
}
maintenant, allez sur ViewController1.h et ajouter la propriété suivante:
@property (weak, nonatomic) id<ViewController1Delegate> delegate;
maintenant si vous créez ViewController1 à L'intérieur de ViewController2 après quelque événement, alors vous devriez le faire de cette façon en utilisant les fichiers NIB:
ViewController1* controller = [[NSBundle mainBundle] loadNibNamed:@"ViewController1" owner:self options:nil][0];
controller.delegate = self;
[self presentViewController:controller animated:YES completion:nil];
Maintenant vous êtes prêt, chaque fois que vous détectez l'événement de contrôle changé dans ViewController1, tout ce que vous avez à faire est le ci-dessous
[delegate checkStateDidChange:checked]; // You pass here YES or NO based on the check state of your control
dites-moi s'il y a quelque chose qui n'est pas clair si je n'ai pas bien compris votre question.
si vous voulez envoyer des données de l'un à l'autre viewController, voici un moyen de le faire:
dire que nous avons viewControllers: viewControllerA et viewControllerB
maintenant en 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];
}
donc c'est comme ça que vous pouvez passer des données de viewControllerA à viewControllerB sans définir tout délégué. ;)
1. crée l'instance du contrôleur de première vue dans le contrôleur de deuxième vue et fait sa propriété @property (nonatomic,assign)
.
2. Assignez l'instance SecondviewController
de ce contrôleur de vue.
2. lorsque vous avez terminé l'opération de sélection Copiez le tableau vers le contrôleur de première vue,lorsque vous déchargez le SecondView ,FirstView conservera les données du tableau.
Espérons Que Cette Aide.
transmission des données entre le premier contrôleur du nouveau au deuxième contrôleur du nouveau comme ci-dessous
"par exemple:
First ViewController String value as
StrFirstValue = @"first";
de sorte que nous pouvons passer cette valeur dans la deuxième classe en utilisant au-dessous de l'étape
1 > nous avons besoin de créer un objet string dans SecondViewController.h fichier
NSString *strValue;
2>nécessité de déclarer les biens comme ci-dessous déclaration .h fichier
@property (strong, nonatomic) NSString *strSecondValue;
3>besoin de synthétiser cette valeur dans FirstViewController.m fichier ci-dessous de l'en-tête de la déclaration
@synthesize strValue;
et dans le premier ViewController.h:
@property (strong, nonatomic) NSString *strValue;
4 > dans FirstViewController,à partir de quelle méthode nous naviguons vers second view s'il vous plaît écrire le code ci-dessous dans cette méthode.
SecondViewController *secondView= [[SecondViewController alloc]
initWithNibName:@"SecondViewController " bundle:[NSBundle MainBundle]];
[secondView setStrSecondValue:StrFirstValue];
[self.navigationController pushViewController:secondView animated:YES ];
je contribue actuellement à une solution open source à ce problème à travers un projet appelé MCViewFactory, qui peut être trouvé ici:
https://github.com/YetiHQ/manticore-iosviewfactory
l'idée est d'imiter le paradigme d'intention D'Android, en utilisant une usine globale pour gérer quelle vue vous regardez et en utilisant" intentions " pour échanger et passer des données entre les vues. Toute la documentation est sur la page github, mais voici quelques faits saillants:
vous configurez toutes vos vues .XIB les classe et les enregistre dans l'app delegate, tout en initialisant l'usine.
// Register activities
MCViewFactory *factory = [MCViewFactory sharedFactory];
// the following two lines are optional.
[factory registerView:@"YourSectionViewController"];
maintenant, dans votre VC, chaque fois que vous voulez passer à une nouvelle VC et passer des données, vous créez une nouvelle intention et ajouter des données à son dictionnaire (savedintancestate). Ensuite, il suffit de définir l'intention actuelle de l'usine:
MCIntent* intent = [MCIntent intentWithSectionName:@"YourSectionViewController"];
[intent setAnimationStyle:UIViewAnimationOptionTransitionFlipFromLeft];
[[intent savedInstanceState] setObject:@"someValue" forKey:@"yourKey"];
[[intent savedInstanceState] setObject:@"anotherValue" forKey:@"anotherKey"];
// ...
[[MCViewModel sharedModel] setCurrentSection:intent];
tous vos points de vue qui se conforment à ce besoin d'être les sous-classes de MCViewController, qui vous permettent d'outrepasser la nouvelle méthode onResume:, vous permettant d'accéder aux données que vous avez transmises.
-(void)onResume:(MCIntent *)intent {
NSObject* someValue = [intent.savedInstanceState objectForKey:@"yourKey"];
NSObject* anotherValue = [intent.savedInstanceState objectForKey:@"anotherKey"];
// ...
// ensure the following line is called, especially for MCSectionViewController
[super onResume:intent];
}
espérons que certains d'entre vous trouvent Cette solution utile/intéressante.
dans mon cas j'ai utilisé une classe singleton qui peut fonctionner comme un objet global permettant des accès aux données de presque partout dans l'application. La première chose est de construire une classe singleton. Veuillez vous référer à la page", Que dois-je Objective-C singleton? "
Et ce que j'ai fait pour rendre l'objet globalement accessible était simplement l'importer dans appName_Prefix.pch
qui est pour appliquer la déclaration d'importation dans toutes les classes.
Pour accéder à cet objet et l'utiliser, j'ai simplement implémenté méthode de classe pour retourner l'instance partagée, qui contient ses propres variables
créer la propriété sur le prochain view controller .h
et définir getter et setter.
ajouter property
dans NextVC.h sur nextVC
@property (strong, nonatomic) NSString *indexNumber;
ajouter
@synthesize indexNumber;
in NextVC.m
et dernier
NextVC *vc=[[NextVC alloc]init];
vc.indexNumber=@"123";
[self.navigationController vc animated:YES];
je sais que c'est un sujet tabassé mais pour ceux qui cherchent à répondre à cette question avec une pente rapide et veulent un exemple de bare-bones, voici ma méthode de go-to pour passer des données si vous utilisez une séquence pour se déplacer.
il est similaire à ce qui précède, mais sans les boutons, étiquettes et autres. Il suffit de passer des données d'un point de vue à l'autre.
Installation De La Table De Montage Séquentiel
Il y a trois parties.
- L'Expéditeur
- La Séquence
- Le Récepteur
c'est un plan de vue très simple avec une séquence entre eux.
Voici la configuration pour l'expéditeur
, Voici la configuration pour le récepteur.
enfin, la configuration pour la suite.
Le Point De Vue Des Contrôleurs
nous gardons ce simple donc pas de boutons, pas d'actions, nous sommes tout simplement déplacer des données de l'expéditeur au récepteur lorsque l'application charge et puis la sortie de la valeur transmise à la console.
cette page prend la valeur initialement chargée et la transmet.
//
// ViewControllerSender.swift
// PassDataBetweenViews
//
// Created by Chris Cantley on 8/25/15.
// Copyright (c) 2015 Chris Cantley. All rights reserved.
//
import UIKit
class ViewControllerSender: UIViewController {
// THE STUFF - put some info into a variable
let favoriteMovie = "Ghost Busters"
override func viewDidAppear(animated: Bool) {
// PASS IDENTIFIER - go to the recieving view controller.
self.performSegueWithIdentifier("goToReciever", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
//GET REFERENCE - ...to the receiver view.
var viewControllerReceiver = segue.destinationViewController as? ViewControllerReceiver
//PASS STUFF - pass the variable along to the target.
viewControllerReceiver!.yourFavMovie = self.favoriteMovie
}
}
cette page envoie juste la valeur de la variable à la console quand il charge. Notre film préféré devrait être dans cette variable.
//
// ViewControllerReceiver.swift
// PassDataBetweenViews
//
// Created by Chris Cantley on 8/25/15.
// Copyright (c) 2015 Chris Cantley. All rights reserved.
//
import UIKit
class ViewControllerReceiver: UIViewController {
//Basic empty variable waiting for you to pass in your fantastic favorite movie.
var yourFavMovie = ""
override func viewDidLoad() {
super.viewDidLoad()
//And now we can view it in the console.
println("The Movie is \(self.yourFavMovie)")
}
}
C'est ainsi que vous pouvez l'aborder si vous voulez utiliser une séquence et que vous n'avez pas vos pages sous un contrôleur de navigation.
une fois qu'il est lancé, il devrait passer automatiquement à la vue du récepteur et passer la valeur de l'expéditeur au récepteur, affichant la valeur dans la console.
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;
délégation est la seule solution pour effectuer de telles opérations lorsque vous utilisez .fichiers xib cependant toutes les réponses décrites ci-dessus sont pour storyboard
pour .fichiers xibs vous devez utiliser délégation. c'est la seule solution que vous pouvez.
une autre solution est d'utiliser la classe singleton pattern initialiser une fois et l'utiliser dans votre application complète.
si vous voulez passer des données de ViewControlerOne à ViewControllerTwo essayez ceux-ci..
ces en ViewControlerOne.h
@property (nonatomic, strong) NSString *str1;
ces en ViewControllerTwo.h
@property (nonatomic, strong) NSString *str2;
synthétise str2 en ViewControllerTwo.m
@interface ViewControllerTwo ()
@end
@implementation ViewControllerTwo
@synthesize str2;
ces en ViewControlerOne.m
- (void)viewDidLoad
{
[super viewDidLoad];
// Data or string you wants to pass in ViewControllerTwo..
self.str1 = @"hello world";
}
sur les boutons cliquez événement faire ceci..
-(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];
}
ces en ViewControllerTwo.m
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(@"%@",str2);
}
vous pouvez enregistrer des données dans App delegate pour y accéder à travers les contrôleurs de vue dans votre application. Tout ce que vous avez à faire est de créer une instance partagée d'app delegate
AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
Par Exemple
si vous déclarez un NSArray object *arrayXYZ
alors vous pouvez y accéder dans n'importe quel contrôleur de vue par appDelegate.arrayXYZ
il y a des tonnes de façons de faire cela et il est important de choisir la bonne. L'une des décisions architecturales les plus importantes réside probablement dans la façon dont le code modèle sera partagé ou consulté dans l'ensemble de l'application.
j'ai écrit un billet de blog à ce sujet il y a quelques temps: partage de Code modèle . Voici un bref résumé:
Partage de données
une approche consiste à partager des pointeurs vers les objets modèles entre les vues contrôleur.
- force Brute itération sur les contrôleurs de vue (dans la Navigation ou la Barre d'Onglet Contrôleur) pour définir les données
- Ensemble de données dans prepareForSegue (si storyboards) ou init (si programmatique)
puisque prepare for segue est le plus commun voici un exemple:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var next = segue.destinationViewController as NextViewController
next.dataSource = dataSource
}
accès indépendant
une autre approche consiste à traiter un écran plein de données à la fois et au lieu de coupler les contrôleurs de vue les uns aux autres, chaque contrôleur de vue à une seule source de données à laquelle ils peuvent accéder indépendamment.
la façon la plus commune que j'ai vu ce fait est un singleton instance. Donc, si votre objet singleton était DataAccess
, vous pourriez faire ce qui suit dans la méthode viewDidLoad D'UIViewController:
func viewDidLoad() {
super.viewDidLoad()
var data = dataAccess.requestData()
}
Il ya des outils supplémentaires qui aident également à transmettre des données:
- Clé-Valeur De L'Observation
- Nnotification
- Base De Données
- Nsfetchedresulscontroller
- Source De Données
Base De Données
ce qui est bien avec les données de base, c'est qu'elles ont des relations inverses. Donc si vous voulez juste donner à un NotesViewController l'objet notes vous pouvez parce qu'il aura un inverse relation avec quelque chose d'autre comme le carnet. Si vous avez besoin de données sur le bloc-notes dans le NotesViewController, vous pouvez remonter le graphe objet en faisant ce qui suit:
let notebookName = note.notebook.name
plus d'informations à ce sujet dans mon billet de blog: Sharing Model Code
si vous voulez envoyer des données de l'un à l'autre viewController, voici un moyen de le faire:
disons que nous avons viewControllers: ViewController et NewViewController.
dans 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
dans 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];
}
Dans NewViewController.h
#import <UIKit/UIKit.h>
@interface NewViewController : UITableViewController
{
NSArray *arrayList;
NSString *name,*age,*dob,*mobile;
}
@property(nonatomic, retain)NSArray *arrayList;
@end
Dans 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
ainsi nous pouvons passer le données d'un viewcontroller vers un autre contrôleur de vue...
j'aime l'idée des objets modèles et des objets simulés basés sur NSProxy pour commettre ou rejeter des données si ce que l'utilisateur sélectionne peut être annulé.
il est facile de transmettre des données puisqu'il s'agit d'un seul objet ou de quelques objets et si vous avez par exemple UINavigationController controller, vous pouvez garder la référence au modèle à l'intérieur et tous les contrôleurs de vue poussée peuvent y accéder directement depuis le contrôleur de navigation.
j'ai vu beaucoup de gens compliquer cela en utilisant la méthode didSelectRowAtPath
. J'utilise des données de base dans mon exemple.
- (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 lignes de code à l'intérieur de la méthode et vous avez terminé.
C'est un très grand tutoriel pour quiconque en veut un. Voici le code exemple:
- (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];
}
}
il y a beaucoup de réponses à ces questions offrant de nombreuses façons différentes d'effectuer la communication du contrôleur de vue qui fonctionnerait en effet, mais je ne vois nulle part où que ce soit mentionné, lequel est réellement le meilleur à utiliser et lequel à éviter.
dans la pratique, à mon avis, seules quelques solutions sont recommandées:
- transmettre les données:
- remplacer la
prepare(for:sender:)
méthode deUIViewController
lorsqu'on utilise une storyboard et enchaîne - passer des données par un initialiseur ou par des propriétés lors de l'exécution de la vue contrôleur des transitions code thtough
- remplacer la
- pour transmettre des données à l'envers
- mettre à jour l'état partagé de l'application (que vous pouvez transmettre entre les contrôleurs de vue avec l'une des méthodes ci-dessus)
- use délégation
- utiliser un dérouleur segue
Solutions je déconseille l'utilisation:
- faisant directement référence au contrôleur précédent au lieu d'utiliser la délégation
- le Partage de données à travers un singleton
- transmission de données par le biais de l'application délégué
- partager des données par défaut par l'utilisateur
- transmettre des données par des notifications
Ces solutions, même si elles fonctionnent à court terme, introduisent trop de dépendances qui vont brouiller l'architecture de l'application et créer plus de problèmes plus tard.
pour les personnes intéressées, j'ai écrit quelques articles qui traitent de ces points plus en profondeur et mettent en évidence les différents inconvénients: