Cette question semble être très populaire ici sur Stack Overflow, alors j'ai pensé que je pourrais essayer de donner une meilleure réponse pour aider les personnes qui débutent dans le monde d'iOS comme moi.
J'espère que cette réponse est suffisamment claire pour que les gens la comprennent et que je n'ai rien oublié.
Transférer les données
Transmettre des données à un contrôleur de vue depuis un autre contrôleur de vue. Vous utiliserez cette méthode si vous souhaitez transmettre un objet/une 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 un BOOL
valeur de ViewControllerA
à ViewControllerB
nous ferions ce qui suit.
-
sur ViewControllerB.h
créer une propriété pour le BOOL
@property (nonatomic, assign) BOOL isSomethingEnabled;
-
sur ViewControllerA
vous devez lui parler de ViewControllerB
utilisez donc un
#import "ViewControllerB.h"
Puis l'endroit où vous voulez charger la vue, par exemple, didSelectRowAtIndex
ou un IBAction
vous devez définir la propriété dans ViewControllerB
avant de le pousser sur la pile de navigation.
ViewControllerB *viewControllerB = [[ViewControllerB alloc] initWithNib:@"ViewControllerB" bundle:nil];
viewControllerB.isSomethingEnabled = YES;
[self pushViewController:viewControllerB animated:YES];
Cela permettra de régler isSomethingEnabled
sur ViewControllerB
à BOOL
valeur YES
.
Transmission des données à l'aide de segments
Si vous utilisez des Storyboards, vous utilisez très probablement des séquences et vous aurez besoin de cette procédure pour transmettre les données. C'est similaire à la procédure ci-dessus 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 ce qui suit :
-
sur ViewControllerB.h
créer une propriété pour le BOOL
@property (nonatomic, assign) BOOL isSomethingEnabled;
-
sur ViewControllerA
vous devez lui parler de ViewControllerB
donc utiliser un
#import "ViewControllerB.h"
-
Créez la transition entre 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 est appelé lorsqu'un enchaînement est effectué. Pour cette raison, nous devons détecter quelle segue a été appelée et ensuite faire quelque chose. Dans notre exemple, nous allons vérifier que "showDetailSegue"
et si cela est effectué, nous passerons notre BOOL
à la valeur ViewControllerB
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([segue.identifier isEqualToString:@"showDetailSegue"]){
ViewControllerB *controller = (ViewControllerB *)segue.destinationViewController;
controller.isSomethingEnabled = YES;
}
}
Si vos vues sont intégrées dans un contrôleur de navigation, vous devez modifier légèrement la méthode ci-dessus pour la remplacer par la suivante
-(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;
}
}
Cela permettra de régler isSomethingEnabled
sur ViewControllerB
à BOOL
valeur YES
.
Renvoi des données
Pour renvoyer les données de ViewControllerB
à ViewControllerA
vous devez utiliser Protocoles et délégués ou Blocs le second peut être utilisé comme un mécanisme de couplage souple pour les rappels.
Pour ce faire, nous allons faire ViewControllerA
un délégué de ViewControllerB
. Cela permet ViewControllerB
pour renvoyer un message à ViewControllerA
nous permettant de renvoyer des données.
Pour ViewControllerA
pour être un délégué de ViewControllerB
il doit être conforme à ViewControllerB
Nous devons spécifier le protocole de l'entreprise. Ceci indique ViewControllerA
les méthodes qu'il doit mettre en œuvre.
-
Sur ViewControllerB.h
en dessous de la #import
mais au-dessus @interface
vous spécifiez le protocole.
@class ViewControllerB;
@protocol ViewControllerBDelegate <NSObject>
- (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item;
@end
-
Suivant toujours dans le ViewControllerB.h
vous devez mettre en place un delegate
et synthétiser en ViewControllerB.m
@property (nonatomic, weak) id <ViewControllerBDelegate> delegate;
-
Sur ViewControllerB
nous appelons un message sur le delegate
quand nous ouvrons le contrôleur de vue.
NSString *itemToPassBack = @"Pass this value back to ViewControllerA";
[self.delegate addItemViewController:self didFinishEnteringItem:itemToPassBack];
-
C'est tout pour ViewControllerB
. Maintenant en ViewControllerA.h
dire ViewControllerA
d'importer ViewControllerB
et se conformer à son protocole.
#import "ViewControllerB.h"
@interface ViewControllerA : UIViewController <ViewControllerBDelegate>
-
Sur 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 dire à ViewControllerB
que ViewControllerA
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é
Centre de notification NSN
C'est un autre moyen de transmettre des données.
// Add an 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];
Transférer des données d'une classe à l'autre (Une classe peut être un contrôleur, un gestionnaire de réseau/session, une sous-classe UIView ou toute autre classe).
Les blocs sont des fonctions anonymes.
Cet exemple transmet les données de Contrôleur B à Contrôleur A
Définir un bloc
@property void(^selectedVoucherBlock)(NSString *); // in ContollerA.h
Ajouter un gestionnaire de bloc (listener)
Où vous avez besoin d'une valeur (par exemple, vous avez besoin de votre réponse API dans ControllerA ou vous avez besoin des données de ContorllerB sur A)
// In ContollerA.m
- (void)viewDidLoad {
[super viewDidLoad];
__unsafe_unretained typeof(self) weakSelf = self;
self.selectedVoucherBlock = ^(NSString *voucher) {
weakSelf->someLabel.text = voucher;
};
}
Aller au contrôleur B
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
ControllerB *vc = [storyboard instantiateViewControllerWithIdentifier:@"ControllerB"];
vc.sourceVC = self;
[self.navigationController pushViewController:vc animated:NO];
Bloc feu
-(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 autre exemple de travail pour les blocs