2009-07-24 9 views
1

Ich versuche meine Hand bei einigen iPhone-Programmierung und ich habe über etwas, das für Veteranen ziemlich offensichtlich sein kann, aber ich weiß nicht genau, warum es passiert ist. Ich habe zwei UIViewController-Klassen und möchte auf eine Methode der anderen Klasse zugreifen. Ich habe zwei NSObject-Klassen, die beiden in IB zugeordnet sind (mit der Class-Datei als UpdateClass für jeden), und ich versuche, eine Klasse zu erstellen und eine Methode aufzurufen. Scheint ziemlich einfach, aber das Problem ist, dass es die Methode aufruft (laut NSLog), aber es aktualisiert die Etiketten nicht. Hier ist mein Code:iPhone - Benutzerdefinierte Klasse wird nicht zugänglich Methode

//UpdateClass.h 
#import <Foundation/Foundation.h> 

@interface UpdateClass : NSObject { 
    IBOutlet UILabel *lbl1; 
    IBOutlet UILabel *lbl2; 
} 

@property (nonatomic, retain) IBOutlet UILabel *lbl1; 
@property (nonatomic, retain) IBOutlet UILabel *lbl2; 

- (void)updateLabels; 

@end 

//UpdateClass.m 

#import "UpdateClass.h" 

@implementation UpdateClass 

@synthesize lbl1; 
@synthesize lbl2; 


- (void)updateLabels { 
    NSString *someWord = @"Whatever"; // This could be anything 
    NSLog(@"NSObject Update"); 
    [lbl1 setText:someWord]; 
    [lbl2 setText:someWord]; 
} 


@end 

//ViewController1.h 
#import <UIKit/UIKit.h> 
@class UpdateClass; 
@interface ViewController1 : UIViewController { 
IBOutlet UIButton *button1; 
NSObject *UpdateClassObject; 
UpdateClass *updateClass; 
} 
@property (nonatomic, retain) IBOutlet UIButton *button1; 
@property (nonatomic, retain) NSObject *UpdateClassObject; 
@property (nonatomic, retain) UpdateClass *updateClass; 
- (void)updateLabels:(id)sender; 
@end 

//ViewController1.m 
#import "ViewController1.h" 
#import "UpdateClass.h" 

@implementation ViewController1 
@synthesize button1; 
@synthesize UpdateClassObject; 
@synthesize updateClass; 

- (void)viewDidLoad { 
    [super viewDidLoad]; 
    updateClass = [[UpdateClass alloc] init]; 
} 

- (void)updateLabels:(id)sender; { //This is connected to TouchDown on button1 
    NSLog(@"Calls UpdateLabels"); 
    [updateClass updateLabels]; //Calls the class method 
} 

//ViewController2.h 
#import <UIKit/UIKit.h> 
@class UpdateClass; 
@interface ViewController2 : UIViewController { 
IBOutlet UIButton *button2; 
NSObject *UpdateClassObject; 
UpdateClass *updateClass; 
} 
@property (nonatomic, retain) IBOutlet UIButton *button2; 
- (void)updateLabels:(id)sender; 
@end 

//ViewController2.m 
#import "ViewController2.h" 
#import "UpdateClass.h" 

@implementation ViewController2 
@synthesize button2; 
@synthesize UpdateClassObject; 
@synthesize updateClass; 

- (void)viewDidLoad { 
    [super viewDidLoad]; 
    updateClass = [[UpdateClass alloc] init]; 
} 

- (void)updateLabels:(id)sender; { //This is connected to TouchDown on button2 
    NSLog(@"Calls UpdateLabels"); 
    [updateClass updateLabels]; //Calls the class method 
} 

So gibt es ein NSObject in IB für beide Ansichten angeschlossen. Es gibt eine Bezeichnung für jede Ansicht, die an das NSObject und den Besitzer der Datei angeschlossen ist (möglicherweise ist es nicht notwendig, sie mit beiden zu verbinden). Wenn die Taste gedrückt wird (die auch in IB richtig angeschlossen ist), soll die Beschriftung zu einer Saite wechseln. NSLog meldet, dass die Methoden aufgerufen werden, die Beschriftungen jedoch nicht geändert werden. Was ist hier falsch?

(Hinweis: Es könnte einige kleine Fehler geben, da ich einige davon eingeben musste, weil ich im Moment nicht den ganzen Code bei mir habe).

+0

im wundern, warum Sie nur eine Klasse verwenden Etiketten zu halten und sie aktualisieren? Ich frage mich auch, ob Sie die Beschriftungen in diesen Klassen zu Ihrer UIViewControllers-Ansicht hinzufügen. – Daniel

+0

Nun, weil ich eine Art zentralisierte Klasse für den Umgang mit Updates gefunden habe, würde Sinn machen ... Aber vielleicht verstehe ich nicht, wie Objective-C programmieren soll Arbeit. –

+0

Das ist wirklich nicht nötig, Sie können nur die Aktualisierung der Etiketten in Ihrem UIView-Controller direkt handhaben, das sind die Controller, mit denen Sie Ihre Ansichten verwalten können. – Daniel

Antwort

0

Wenn die NSLog() läuft, aber die Etiketten nicht aktualisieren, ist es fast sicher, dass lbl1 und lbl2 sind Null. Sie sind fast sicher Null, weil sie nicht wirklich in IB verbunden sind, oder Sie führen diesen Code vor -viewDidLoad ausgeführt. In Ihrem Design hier müssen Sie -updateLabels vermeiden, bis die Ansicht tatsächlich ihre Ausgänge geladen und verdrahtet hat. Ansichten werden langsam geladen, sodass diese Beschriftungen nicht vor dem ersten Anzeigen der Ansicht erstellt werden. Die kurze Version ist, dass Sie -updateLabels in -viewDidLoad anrufen sollten.

+0

Wie sollte das gehandhabt werden, wenn sich die Werte ändern? Wie in einem echten Programm könnte die SomeWord-Zeichenfolge eine sich ändernde Variable sein. Ist das ein schlechter Weg, ein Programm einzurichten, das den Text der Etiketten ziemlich oft ändert? –

+0

Wenn sich der Text häufig ändert, sollten Sie wahrscheinlich Benachrichtigungen verwenden, um die Benutzeroberflächenelemente auf dem neuesten Stand zu halten. Es sollte ein Model-Objekt geben, das die Daten enthält, die Sie darstellen. Wenn sich die Daten ändern, sollte eine Benachrichtigung gesendet werden. Der ViewController sollte, wenn er sichtbar ist (und nur wenn er sichtbar ist), diese Benachrichtigung beachten und die Beschriftung aktualisieren, damit sie mit dem neuen Wert übereinstimmt. Sie sollten -viewWillAppear/Disappear verwenden, um die Benachrichtigungen zu abonnieren und abzubestellen. http://developer.apple.com/documentation/Kakao/Konzeptionelle/Benachrichtigungen/http://robnapier.net/blog/thoughts-nsnotifications-42 –

0

OK, es gibt einige Aspekte dieses Codes, die verwirrend sind. Daher beginne ich mit der offensichtlichen Unterscheidung, die Sie zwischen Objekten und Klassen treffen.

Was ist der Zweck:

NSObject *UpdateClassObject; 

Was ist das? Wie ist es zugeordnet (von einer Feder?)? Von den Namen, es scheint, dass Sie einfach eine Instanz der Klasse UpdateClass wollen, das ist der Zweck:

UpdateClass *updateClass; 

Sie erscheinen nicht die andere durch zu sein, so bin ich nicht sicher, warum es da ist überhaupt .

Nun zum Kern Ihres Problems: Sie rufen [updateClass updateLabels] und Ihre NSLog-Anweisung zeigt an, dass es tatsächlich aufgerufen wird. Was mir sagt, dass das wahrscheinlichste Problem beide Instanzen Ihrer Etiketten sind lbl1 und lbl2 sind in der Tat nil. Denken Sie daran, dass in Objective-C das Senden einer Nachricht (wie updateText: in diesem Fall) an nil keine Fehler auslöst, sondern einfach fehlschlägt.

Also warum sind sie null? Nun, sie sind als IBOutlet s deklariert, was mich denken lässt, dass Sie eine NIB-Datei haben, deren Dateieigentümer UpdateClass ist, was die tatsächliche Verdrahtung von einigen UILabel s zu Ihren Mitgliedsvariablen macht.Wenn dies richtig ist, dann müssen Sie updateClass mit dem NIB initialze richtig:

updateClass = [[UpdateClass alloc] initWithNibName:@"UpdateClass" bundle:nil]; // or whatever the nib is called 

Aber was machst du eigentlich ist:

updateClass = [[UpdateClass alloc] init]; 

Dies bedeutet, dass die Klasse nie von einem NIB initialisiert und Ihre Etiketten werden niemals verdrahtet.

Ein letzter Punkt, das Wort 'Class' in Ihren Klassennamen ist ziemlich redundant - es ist offensichtlich eine Klasse. Dies kann auch zu Verwirrung führen - die Instanzvariable, in der Sie Ihre Instanz von UpdateClass speichern, heißt updateClass - das würde bedeuten, dass sie tatsächlich eine Instanz eines Objekts speichert, dessen Typ Class ist (was Sie durch Aufruf von [SomeClass class] erhalten könnten).

0

Sie senden die Meldung updateLabels an die falsche UpdateClass.

Sie haben angegeben, dass Sie in InterfaceBuilder eine Instanz von UpdateClass angeschlossen haben, die auch die Verbindungen zu den in IB festgelegten Labels hat. Wenn Ihre Ansicht geladen ist, wird daher das UpdateClass-Objekt bereits von der NIB injiziert.

In Ihrer ViewDidLoad -Implementierung erstellen Sie eine neue Instanz von UpdateClass. In dieser Instanz sind die Beschriftungen nicht festgelegt (sie sind null). Sobald Sie also die updateLabels-Methode an dieses Objekt gesendet haben, enthält dieses Objekt keine zu aktualisierenden Labels.

Werfen Sie einfach die Deklaration und Zuweisung von updateClass in viewDidLoad und senden Sie die updateLabels Nachricht an UpdateClassObject. Ziehen Sie in Betracht, das Member UpdateCLassObject in updateClass umzubenennen oder besser noch die Klasse in "updater" umzubenennen. Erwägen Sie auch, stattdessen eine Basisklasse zu verwenden.

1

Ein Wort auf Design hier:

Sie scheinen einige Funktionen unter zwei oder mehr View-Controller-Implementierungen teilen zu wollen. In diesem Fall möchten Sie möglicherweise eine allgemeine Basisklasse erstellen, die von UIViewController abgeleitet ist und Ihre zwei Ansichten von dieser Klasse ableitet. Das BaseView würde die Ausgänge für allgemeine UI-Komponenten deklarieren, die Sie in IB verbinden können.

@interface BaseUIViewController : UIViewController { 
    IBOutlet UILabel *lbl1; 
    IBOutlet UILabel *lbl2; 
} 

@property (nonatomic, retain) IBOutlet UILabel *lbl1; 
@property (nonatomic, retain) IBOutlet UILabel *lbl2; 

- (void)updateLabels; 

@end 

...

@interface ViewController1 : BaseUIViewController { 
    IBOutlet UIButton *button1; 

...

Verwandte Themen