2011-06-23 5 views
2

Je développe sur iOS et je construis mes vues par programme. J'ai remarqué que lorsque j'essaie d'accéder à des variables qui doivent être modifiées à partir du contrôleur de vue, elles sont nulles. Je posterai à la fois la vue et son contrôleur de vue:iOS accédant à la variable vue du contrôleur de vue

RootViewController.h

#import <UIKit/UIKit.h> 

@class RootView; 

@interface RootViewController : UIViewController { 
    RootView *rootView; 
} 

@property (nonatomic,retain) RootView *rootView; 


@end 

RootViewController.m

#import "RootViewController.h" 
#import "RootView.h" 

@implementation RootViewController 

@synthesize rootView; 

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 
{ 
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; 
    if (self) { 
     // Custom initialization 
    } 
    return self; 
} 



- (void)dealloc 
{ 
    [rootView release]; 
    [super dealloc]; 
} 

- (void)didReceiveMemoryWarning 
{ 
    // Releases the view if it doesn't have a superview. 
    [super didReceiveMemoryWarning]; 

    // Release any cached data, images, etc that aren't in use. 
} 

#pragma mark - View lifecycle 

- (void)loadView{ 
    RootView *rootV = [[RootView alloc] initWithFrame:CGRectMake(10, 10, 100, 50)]; 
    rootV.rootViewController = self; 
    self.view = rootV; 
    [rootV release]; 
} 

- (void)viewDidLoad{ 
    NSLog(@"TEXT: %@",self.rootView.label.text); 
    [email protected]"HELLO!"; 
} 

- (void)viewDidUnload 
{ 
    [super viewDidUnload]; 
    // Release any retained subviews of the main view. 
    // e.g. self.myOutlet = nil; 
    [self setRootView:nil]; 
} 

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation 
{ 
    // Return YES for supported orientations 
    return (interfaceOrientation == UIInterfaceOrientationPortrait); 
} 

@end

RootView.h

#import <UIKit/UIKit.h> 

@class RootViewController; 

@interface RootView : UIView { 
    RootViewController *rootViewController; 
    UILabel *label; 
} 

@property (nonatomic,assign) RootViewController *rootViewController; 
@property (nonatomic,retain) UILabel *label; 


@end 

RootView.m

#import "RootView.h" 
#import "RootViewController.h" 

@implementation RootView 
@synthesize rootViewController; 
@synthesize label; 

- (id)initWithFrame:(CGRect)frame 
{ 
    self = [super initWithFrame:frame]; 
    if (self) { 
     //Create the label 
     UILabel *testLabel = [[UILabel alloc] initWithFrame:CGRectMake(100, 100,100, 50)]; 
     //Set the font bold 
     testLabel.font = [UIFont boldSystemFontOfSize:20.0]; 
     //Set the backgroundcolor of the label to transparent 
     testLabel.backgroundColor = [UIColor clearColor]; 
     //Set the text alignment of the text label to left 
     testLabel.textAlignment = UITextAlignmentLeft; 
     //Set the text color of the text label to black 
     testLabel.textColor = [UIColor blackColor]; 
     testLabel.text = @"01:30"; 

     self.label = testLabel; 

     [self addSubview:label]; 
     [testLabel release]; 
    } 
    return self; 
} 


- (void)dealloc 
{ 
    [label release]; 
    rootViewController = nil; 
    [super dealloc]; 
} 

@end 

J'ai changé le code, mais il semble ne fonctionne pas .....

Ok j'ai oublié résolu cette ligne "self.rootView = rootv;"

Répondre

2

Votre vue ne trouve pas ce que son contrôleur est avant que sa méthode -initRootView ne revienne, mais vous essayez d'utiliser le contrôleur à l'intérieur de cette méthode. Cela dit, il serait préférable que vous suiviez le modèle Cocoa Touch habituel pour un contrôleur de vue créant sa vue. Les contrôleurs de vue sont censés créer leurs vues paresseusement, c'est-à-dire qu'ils reportent la création et l'initialisation de vue jusqu'à ce que la méthode -loadView soit appelée. Vous pouvez substituer -loadView pour créer votre vue, et surcharger -viewDidLoad pour effectuer tout travail d'installation qui doit être effectué après la création de la vue.

De même, il est généralement déconseillé à une vue de connaître son contrôleur. Le contrôleur doit indiquer à la vue quoi faire, et non l'inverse. Si vous avez besoin de la vue pour envoyer des informations au contrôleur, vous fournissez généralement le contrôleur à la vue en tant que délégué de la vue. Mais si vous avez juste besoin du contrôleur de vue pour trouver une sous-vue, comme votre étiquette, c'est probablement une bonne idée de fournir des accesseurs dans la vue conteneur pour que le contrôleur de vue puisse juste dire quelque chose comme self.view.label.text = @"some text";. options est de définir la propriété tag de la sous-vue à une valeur unique et que le contrôleur utilise pour trouver la sous-vue

+0

Désolé je n'ai pas compris. Ce que j'essaie de faire si j'ai bien compris, c'est d'avoir des prises dans mon contrôleur de vue selon le MVC et du contrôleur de vue je veux changer les attributs de l'étiquette est-ce correct? J'ai essayé d'ajouter un bouton et quand j'appuie sur le bouton j'essaie de changer le texte de l'étiquette mais ça ne marche pas. Semble la référence à l'étiquette est nulle..une suggestion ?! – ubiAle

+0

J'espère que mon édition aidera à clarifier les choses, mais vous voudrez également lire sur [Comprendre le cycle de gestion de vue] (http://tinyurl.com/6cw5352) dans les docs. – Caleb

+0

Donc, selon le modèle de contact de cacao habituel dois-je construire la vue dans la méthode loadview? Si oui, est-ce mal d'avoir la vue dans un fichier séparé comme je l'ai fait et d'instancier l'affichage dans la méthode loadview? Est-ce différent de ce que j'ai fait ou pas ?! Merci – ubiAle

0

Vous ne savez pas pourquoi vous le faites, mais vous pourriez probablement le faire fonctionner si vous passez le contrôleur dans init de la vue:

RootView *rootV = [[RootView alloc] initRootView:self]; 

vue init:

- (id)initRootView:(UIViewController*)controller 
{ 
    self.rootViewController = controller; 
    self.rootViewController.rootViewLabel = testLabel; 
+0

Quelle est la différence de le faire plutôt que j'ai fait ?! N'est-ce pas la même chose? – ubiAle

+0

dans votre initRootView, vous avez 'self.rootViewController.rootViewLabel = testLabel;' mais self.rootViewController ne pointe pas encore vers votre contrôleur. – meggar

+0

Oh c'est vrai !! Je l'ai!!!Merci – ubiAle

1

Le problème est facile à repérer, mais nécessite un travail de réparation.

En regardant votre code, quelque chose que je veux immédiatement suggérer est de mettre tout votre code d'initialisation RootView la méthode loadView de votre RootViewController. C'est là où il devrait être (see here why).

En outre, si vous avez absolument besoin de votre RootView pour avoir une référence à RootViewController, vous devriez probablement le faire en viewDidLoad. Mais je ne recommanderais pas de le faire. Lors de l'utilisation du modèle MVC, le contrôleur a la responsabilité d'initialiser et de mettre à jour les vues. La ligne self.rootViewController.rootViewLabel = testLabel; doit être supprimée de l'implémentation de RootView. Votre intention n'est pas claire, mais si vous voulez que le rootViewLabel soit mis à jour, vous devriez laisser le contrôleur le faire.

Pour résumer:

// RootViewController.m 

- (id)initRootViewController{ 

    self = [super init]; 

    if(self){ 
     // other init code here 
    } 

    return self; 
} 

- (void)loadView { 
    RootView *rootV = [[RootView alloc] initWithFrame:CGRectMake(0, 0, 100, 50)];   
    self.view = rootV; 
    [rootV release];  
} 

- (void)viewDidLoad { 
    [super viewDidLoad];   
    // etc... 
} 

// etc. 

Maintenant, pour RootView, voici ce qu'il ressemblerait à ceci:

RootView.h

#import <UIKit/UIKit.h> 

@interface RootView : UIView {  
    UILabel *rootViewLabel; 
} 

// moved from RootViewController 
@property (nonatomic, retain) UILabel *rootViewLabel; 

@end 

RootView. m

#import "RootView.h" 

@implementation RootView 

@synthesize rootViewLabel; 

- (id)initWithFrame:(CGRect)frame 
{ 
    self = [super initWithFrame:frame]; 
    if (self) { 
     // Whatever initialization code you might have 
     //Create the label 
     UILabel *testLabel = [[UILabel alloc] initWithFrame:CGRectMake(100, 100,100, 50)]; 
     //Set the font bold 
     testLabel.font = [UIFont boldSystemFontOfSize:20.0]; 
     //Set the backgroundcolor of the label to transparent 
     testLabel.backgroundColor = [UIColor clearColor]; 
     //Set the text alignment of the text label to left 
     testLabel.textAlignment = UITextAlignmentLeft; 
     //Set the text color of the text label to black 
     testLabel.textColor = [UIColor blackColor]; 
     testLabel.text = @"01:30"; 

     self.rootViewLabel = testLabel;  
     [testLabel release]; 

     // add rootViewLabel as a subview of your this view 
     [self addSubView:rootViewLabel]; 
    } 
    return self; 
} 

- (void)dealloc 
{ 
    [rootViewLabel release]; 
    [super dealloc]; 
} 

@end 

J'espère que cela vous donne une idée sur la façon de structurer votre point de vue du code d'initialisation ...

(Avertissement, je ne peux pas tester ce code maintenant, s'il vous plaît signaler toute erreur! Merci)

+0

Merci pour votre message, L'idée était d'avoir un fichier séparé pour la vue, puisque je dois écrire beaucoup de lignes je préférerais avoir des fichiers séparés, je pense que ce n'est pas un problème d'avoir les lignes que vous avez écrites viewDidLoad dans la méthode initwithframe que vous appelez dans la vue load n'est-ce pas ?! Si je sépare la vue et le viewcontroller, comment le contrôleur peut-il connaître sa sortie? Je veux dire si je dois supprimer cette ligne "self.rootViewController.rootViewLabel = testLabel" comment puis-je changer mes prises au cas où j'ai 2 fichiers différents un pour la vue et un pour son viewcontroller? – ubiAle

+0

Oui, dans ce cas, vous devez implémenter UILabel en tant que propriété de votre RootView. Je mettrai à jour le code dans ma réponse pour refléter cela. Ensuite, le contrôleur y accéder via la notation par points de propriété: 'self.rootView.rootViewLabel'. – octy

+0

Réponse mise à jour. – octy

Questions connexes