PDA

View Full Version : Hoe de Value ve Label in IB binden aan class geinstantieerd door AppController


Annunaki
26 juli 2009, 15:26
Yo guys,

I ben dus nog vanalles aan het leren, en ben gestart met het proberen programmeren in Objective-C, XCode en Interface Builder, maar ik loop nu al tegen een probleem / vraagje, en ik hoop dat misschien iemand hier mij in de juiste richting kan helpen.

Ik heb een Classe :


@interface LoginClass : NSObject
{
NSString *userName;
NSString *password;
NSString *secret;
BOOL connected;
}

- (void)logIn;
- (void)logOut;

- (id)initWithLogin:(NSString *)aLogin password:(NSString *)aPassword;

@property (readwrite, copy) NSString *userName;
@property (readwrite, copy) NSString *password;
@property (readonly) NSString *secret;
@property (readonly) BOOL connected;


Van deze Class wordt een instantie gemaakt in mijn AppController en die gebruik ik dan om bepaalde zaken te doen wanneer er bv een knop ingedrukt wordt op een scherm. Mijn Class zelf doet wat hij moet doen, en logt vanalles d.m.v. NSLog zodat ik kan zien wat er gebeurd. Properties worden ingevuld, de LogIn & LogOut worden mooi aangeroepen, ...

Mijn AppController ziet er zo uit :


@interface AppController : NSObject
{
IBOutlet NSTextField *userName;
IBOutlet NSTextField *password;
// IBOutlet NSTextField *secret;
IBOutlet NSWindow *window;

LoginClass * LoginClass;
}

- (IBAction)connect:(id)sender;


De implementatie van Connect heb ik in IB gekoppeld aan een button, en die wordt dus perfect uitgevoered wanneer er op de knop geklikt wordt. De code in de Connect ziet er ongeveer als volgt uit :


- (IBAction)connect:(id)sender
{
// Create an instance of our LoginClass
LoginClass = [[LoginClass alloc] initWithLogin:[userName stringValue] password:[password stringValue]];

// Now that we have our LoginClass we can start to work with it.
[LoginClass logIn];

...
}


In de logIn code van mijn class vull ik de secret property op met een dummy string, ook dat werkt perfect.

Waar ik echter niet in slaag is om de Value van een Label in IB te binden aan de secret property van mijn LoginClass. Ik heb nu reeds vanalles geprobeerd zonder succes.

Een object toevoegen in IB voor mijn LoginClass en de value dan binden aan de secret key van dat object lukt niet (geen errors, maar waarde wordt niet weergegeven, text van de label is leeg).

Ook reeds geprobeerd aan de hand van de AppController met de LoginClass.secret key, maar zelfde resultaat (geen dus).

Ik vermoed dat ik ergens iets verkeerd doe, of ergens iets over het hoofd zie, maar ik zie niet onmiddellijk wat, dus hoop ik dat iemand mij hier misschien in de juiste richting kan wijzen.


Met dank bij voorbaat,



Stefaan

t21
26 juli 2009, 16:26
Hey Stefaan,

Als je een object toevoegt in IB wordt dat geinitialiseerd in IB, en is dus een verschillend object dan dat wat je in je AppController initialiseert.

Maar ook nog een vraagje: waarom initialiseer je je login-object in de connect-methode, en niet in de init?

Bad idea, want iedere keer er iemand op de loginbutton zal klikken wordt er een nieuw object gemaakt, en geraakt er eentje unreferenced. Een lek dus... Ik zou die klasse opnieuw inrichten, zonder die gekke init-method, en dan dat object in de init van de appcontroller alloceren en initialiseren. Je kan dan de values doorgeven in de connect-methode als een gewone functie...



Maar om te antwoorden op je vraag:

Het makkelijkste wat je kan doen is returnvalues terugkeren vanuit je login-object via een methode (die aldanniet iets nuttigs doet), en die dan parsen in je appcontoller connect-method en het label setten.

Moeilijker optie is een referentie maken in je login-klasse naar de appcontroller-klasse, en dan kan je daar rechtstreeks de IBOutlet setten. Maar dat is niet echt een goed idee voor de onderhoudbaarheid van je code.

Nog een andere opties werken met een NSNotification of NSTimer, maar die zijn overkill voor wat je hier wil doen...

De eerste lijkt me het eenvoudigst te implementeren, en ook meest duidelijk in je code :-)

Hopelijk helpt dit je wat.

Bye!

D.

Annunaki
26 juli 2009, 16:38
Hoi D,

Ja, dat van het instantiëren van het object in de Connect heb ik reeds aangepast, had dat stukje code reeds verplaatst naar de awakeFromNIB methode (waar ik nog een aantal andere GUI elementen voorzien van hun default waardes).

Maar als ik uw dingen lees, dan heb je wel gelijk, het komt beter in de Init methode van mijn AppController, en die properties kunnen idd meegegeven worden in de logIn methode. Ik ga dat nog allemaal aanpassen, maar wou eerst dat Bindings ding in orde krijgen.


Ondertussen heb ik immers nog wat zelf zitten experimenteren en heb ik alles in orde gekregen :-) Ik heb het als volgt gedaan en het blijkt te werken (heb trouwens 2 oplossingen, misschien kan jij even meegeven wat de beste is)

1 ) Gewoon via de AppController

De Value van die label binden aan AppController d.m.v. de LoginClass.secret key. Dat had ik dus, maar er kwam niks op mijn scherm. Nu had ik al willChangeValueForKey dingen in de property setters van mijn LoginClass object, maar nog niet in de AppController.


// Now that we have our LoginClass we can start to work with it.
[self willChangeValueForKey:@"LoginClass"];
[LoginClass logIn];
[self didChangeValueForKey:@"LoginClass"];


En pats, het werkte :-)

2 ) Ik had ook nog geprobeerd een ObjectController toe te voegen in IB, die koppelen aan AppController.LoginClass en dan mijn label te binden aan de secret key van die ObjectController, met als zelfde resultaat (het werkte ook na die willChangeValueForKey en didChangeValueForKey zaken.


Wat is nu eigenlijk de beste van die twee ?


Wel een beetje jammer dat ik bij iedere wijziging in mijn LoginClass ook die ChangeValueForKey zaken moet toevoegen will ik de interface ook up to date houden. Bestaat daar een alternatief voor, of heb je mischien een betere werkwijze ?






Enfin, 't is in orde gekomen (wel een dat zitten knoeien, en toen ik de post gemaakt had is mijnen euro precies beginnen vallen). Mocht je nog interessante tips, tricks, sites en andere hebben, laat ze maar komen. Ik heb nog heel veel te leren, maar nu dat ik mijn probleem toch zelf heb kunnen oplossen ben ik benieuwd naar meer :-)



Groeten,




Stefaan

t21
26 juli 2009, 17:20
Nu ja, ik probeer mezelf altijd uit IB te houden, dus ik ben van mening dat de eerste methode ietsje cleaner is.

Al wat die willChange en didChange-methodes doet is de appcontroller melden dat er waarschijnlijk ergens iets veranderd is in de values van het object LoginClass, en dan gaat die dan duidelijk maken aan de andere objecten (de observers, zoals men dat noemt) dat er iets veranderd is.
Lees: AppController je zegt dan tegen Label dat zijn gebonden value veranderd is en die gaat dan zichzelf updaten - dus zonder dat jij impliciet moet zeggen dat er iets veranderd is voor label.

Als je geen zin hebt om altijd iets te doen met die code kan je iets doen met NSNotifications. Je Login-object stuurt dan gewoon iets uit als de value veranderd is, en in je appcontroller maak je dan een method die het label aanpast. Voordeel hiervan is is dat je niks met je login-object moet binden in de IB - je hebt daar dan enkel je appcontroller.


(De willChange en didChange-methodes gecombineerd met die IB-bindings lijken me not altijd een beetje een complexe oplossing voor wat je wil doen...)

D.

Annunaki
26 juli 2009, 18:47
Dat moet die NSNotificactions ga ik even moeten uitzoeken, daar heb ik nog niet echt iets over gelezen. Ben nog maar een paar dagen gestart met Objective-C en zo. Ben al blij dat ik het gevonden had :-)

Groeten,



Stefaan