Edellisessä osassa esiteltiin tapa yksinkertaistaa muistinhallintaa tekemällä luokkamuuttujista propertyja. Tällä kertaa syvennytään hieman siihen miten ja milloin Objective-C kutsuu retain ja release metodeja objekteille. Lopuksi vielä muutama huomautus objektien säilömisestä kokoelmien sisällä.
Alla olevassa EsimerkkiYksi.h tiedostossa on esitelty muuttuja minunTeksti, josta on tehty property. Objective-C luo propertyille automaagisesti mutator-metodit eli metodit joilla muuttujan sisältöä voidaan helposti manipuloida.
EsimerkkiYksi.h
@interface EsimerkkiYksi : NSObject { NSString *minunTeksti; } @property(nonatomic,retain) NSString *minunTeksti; -(void)esimerkkiMetodi; @end
Alla olevassa Esimerkki.m tiedostossa on havainnollistettu miten minunTeksti objektia voidaan käsitellä gettereilla ja settereilla.
EsimerkkiYksi.m
@implementation EsimerkkiYksi @synthesize minunTeksti; -(void)esimerkkiMetodi { //Asettaa minunTeksti muuttujaan tekstin "Mun teksti!" self.minunTeksti = [NSString stringWithString: @"Mun teksti!"]; //Tekee saman asian eri syntaksilla. [self setMinunTeksti: [NSString stringWithString: @"Mun teksti!"]]; NSLog(@"Teksti: %@", minunTeksti); NSString *toinenTeksti; //Asettaa toinenTeksti muuttujan viittaamaan minunTeksti muuttujaan. toinenTeksti = self.minunTeksti; NSLog(@"Toinen teksti: %@", toinenTeksti); //Sama asia eri syntaksilla. toinenTeksti = [self minunTeksti]; NSLog(@"Toinen teksti: %@", toinenTeksti); } @end
Ohjelmoija voi myös korvata muuttujiensa mutator-metodit haluamillaan. Yläpuolella olevaan EsimerkkiYksi luokan tapauksessa metodit voisi kirjoittaa auki seuraavanlaisesti:
-(NSString*)minunTeksti { return minunTeksti; } -(void)setMinunTeksti:(NSString*)uusiTeksti { //Nostaa uusiTeksti muuttujan retainCounttia yhdellä. "Ottaa vastuun objektista" [uusiTeksti retain]; //Vapauttaa minunTeksti muuttujan. [minunTeksti release]; //Asettaa minunTeksti muuttujan. minunTeksti = uusiTeksti; }
Jos kyseiset metodit sisällytetään luokkaan niitä kutsutaan aina, kun minunTeksti muuttujaa pyydetään tai asetetaan self notaation kautta. Mahdollisia ongelmatilanteita syntyy jos setterin sisällä kutsutaan retain ja release metodeja väärissä järjestyksissä. Toinen asia mikä pitää muistaa luodessa omia mutator-metodeja on se, ettei niiden sisällä pidä koskaan käyttää self notaatiota.
Alla esimerkki tilanteesta, jossa ohjelma menee loputtomaan looppiin, koska ohjelmoija käyttää getter-metodin sisällä self notaatiota. Jos olet epävarma on parasta olla muokkaamatta propertyille luotuja mutator-metodeja.
//EI NÄIN!!!! -(NSString*)minunTeksti { return self.minunTeksti; }
Tapauksissa, joissa objekteja säilötään esimerkiksi NSArray tai NSDictionary kokoelmien sisällä on huomioitavaa, että sisään syötettäville objekteille kutsutaan automaattisesti retain metodia. Muistivuotojen välttämiseksi kokoelmiin tulee syöttää vain autoreleasettuja objekteja, ellei objektin oleteta säilyvän kokoelman tuhoutumisen jälkeen. Alla esimerkki kokoelmien käytöstä.
-(void)populoiArray { //EI NÄIN!!! NSString *testi = [[NSString alloc] initWithString: @"Testi teksti!"]; self.testiArray = [NSArray arrayWithObject: testi]; //testi muuttuja ei ole autoreleasettu. Muistivuoto syntyy, kun testArray tuhotaan. } -(void)populoiToinenArray { //NÄIN NSString *testi = [NSString stringWithString: @"Testi teksti!"]; self.testiArray = [NSArray arrayWithObject: testi]; //testi muuttuja on autoreleasettu, testiArray ottaa sen haltuun ja vapauttaa sen, kun testArray tuhotaan. }