NSString versus NSMutableString
26 oktober 2003 - 08:09   
geplaatst door: bert
NSString zou voor strings zijn die je niet kunt wijzigen.

NSString * x;

x = @"Bert";
x =  @"MacFreak";

werkt echter wel. Dus toch te wijzigen? Waar zit het verschil?

Bert

NSString versus NSMutableString
26 oktober 2003 - 10:37    reactie #1
geplaatst door: ridmaur
Je wijzigt hier niet de string, je wiijzigt waar de NSString pointer genaamd x naar wijst. Of naar de string "Bert", of naar de string "MacFreak".
Je kan echter niet karakters toevoegen of verwijderen aan de string met NSString. Daar heeft NSString geen methodes voor, NSMutableString daarentegen wel.

Illustratie:
NSString *name = @"Fred";
NSString *group= @"MacFreak";
NSMutableString *s;

[s appendString: name];
[s appendString: @" is lid van "];
[s appendString: group];

NSMutableString wordt echter niet veel gebruikt. Veelal wordt er gewoon een nieuwe NSString gedefinieerd wanneer er bijv. twee strings aan elkaar moeten worden geplakt.


NSString *name = @"Fred";
NSString *group= @"MacFreak";

NSString *message = [ [name stringByAppendingString:@" is lid van "] stringByAppendingString:group];

groeten,
Rob
NSString versus NSMutableString
26 oktober 2003 - 14:22    reactie #2
geplaatst door: bert

Bedankt voor je reactie met uitleg.


Citaat
ridmaur om 10:37, 26-10-2003

Citaat
bert om 8:09, 26-10-2003
NSString zou voor strings zijn die je niet kunt wijzigen.

NSString * x;

x = @"Bert";
x =  @"MacFreak";

werkt echter wel. Dus toch te wijzigen? Waar zit het verschil?

Bert

Je wijzigt hier niet de string, je wiijzigt waar de NSString pointer genaamd x naar wijst. Of naar de string "Bert", of naar de string "MacFreak".

Duidelijk. Maar betekent dat stukje code van mij dan ook een geheugenlek(je)? Ik denk nl dat Bert in het geheugen blijft staan en er niets meer is dat er naar wijst. Zo ja, hoe los ik dat op?

bert

NSString versus NSMutableString
26 oktober 2003 - 14:59    reactie #3
geplaatst door: ridmaur
Aha, geheugenbeheer in Cocoa..... Ik doe een poging, maar dit is niet een van de eenvoudigste onderdelen van Cocoa/Objective C.

In het algemeen: Als je de NSString definieert binnen een methode, bijv. om een tijdelijke string manipulatie te doen hoef je je geen zorgen te maken. Bij het verlaten van de methode wordt de NSString automatisch vernietigd. Vb:

- (void)doSomething
{
  NSString *theString;
  .....
  [theString doSomethingToIt];
  ....
}


Anders wordt het als je een NSString als instantie variable hebt van je class of als je een NSString meegeeft als parameter aan een method (bijv. om de waarde van een instantie te zetten). Dan komt geheugen management om de hoek kijken. In onderstaand voorbeeld wordt NSString theString gedefinieerd als instance variable van TheClass. Om de waarde van die instance variable uit te kunnen lezen en te kunnen schrijven worden twee accessor methods gedefinieerd: theString en setTheString... Immers, goed OO gebruik is dat je directe toegang tot je instance variables afschermt en de toegang regelt d.m.v. 'getters and setters'.

@interface TheClass:NSObject
{
     NSString *theString;
}

- (void)setTheString(NSString *s);
- (NSString *)theString;


De implementatie van de 'accesor methods' setTheString en theString zien er als volgt uit:

- (void)setTheString(NSString *s)
{
  [s retain];
  [theString release];
  theString = s;
}

- (NSString *)theString
{
  return theString;
}

Daarnaast moet je n de init methode van de class theString alloceren;
- init
{
  ...
  ...
  NSString *theString = [[NSString alloc] init];
  ...
}

En in de de dealloc methode van de class moet je de theString ook niet vergeten te dealloceren:

- (void)dealloc
{
  ...
  ...
  [theString release];
}

Elk object kent een retain count; een tellertje dat bijhoudt hoeveel andere objecten een referentie hebben uitstaan naar het object. Dit tellertje wordt automatisch opgehoogd met een referentie maar kan ook handmatig worden opgehoogd met de methode retain en verlaagd met de methode release. Pas als een object een retain count heeft van 0 kan het netjes worden opgeruimd. Als je de retain count van je objecten in je programma niet in de gaten houdt, creeer je potentiele memory leaks omdat objecten nooit kunnen worden opgeruimd omdat je ze niet netjes weer vrijgeeft. In het voorbeeld van setTheString wordt theString gereleased voordat je de waarde toekent. Anders zou de retainwaarde op 2 komen (1 bij initialisatie en 1 in theSetString methode) maar je wilt alleen de waarde van theString wijzigen. Als je retain niet had gedaan in setTheString en je had het object theObject van class TheClass vernietigd, dan had theString niet vernietigd kunnen worden, want de release in de dealloc van de class was niet voldoende geweest om de retain count op 0 te zetten en aldus theString vrij te geven voor 'garbage collection'.

Meer info over geheugenmanagement (alloc, init, retain, release, autorelease, dealloc) kan je vinden in de Cocoa documentatie. En ook in dit artikel: http://cocoadevcentral.com/articles/000055.php

groeten,
Rob
NSString versus NSMutableString
26 oktober 2003 - 16:44    reactie #4
geplaatst door: bert
Beste Rob,

Je hebt een uitgebreider antwoord gegeven dan ik bedoelde (dat met die tellertjes snap ik wel, en vind ik reuze elegant), maar ik begrijp uit het eerste gedeelte dat ik me over mijn voorbeeld geen zorgen hoef te maken: Geen geheugenlek.

Het artikel dat je noemde had ik vanmiddag nog zitten lezen! Daarmee werd alles weer ietsje duidelijker, maar nog (lang) niet helemaal. Enfin, doorploegen maar!

Bert

NSString versus NSMutableString
26 oktober 2003 - 18:18    reactie #5
geplaatst door: bert
Nog een probleempje met strings:

Als ik een object foo van het type NSMutableString maak, reageert dat niet op de uppercaseString message die ik 'm zend

[foo uppercaseString]

Dat lukte wel toen het een NSString pointer was.
bar = [foo uppercaseString];

NSMutableString inherit toch van NSString?

:confused:

Bert

NSString versus NSMutableString
26 oktober 2003 - 21:16    reactie #6
geplaatst door: ridmaur
Volgens de Cocoa docs:

- (NSString *)uppercaseString
Returns a string with each character from the receiver changed to its corresponding uppercase value. Case transformations aren’t guaranteed to be symmetrical or to produce strings of the same lengths as the originals. See lowercaseString for an example.

uppercaseString retourneert altijd een NSString, kortom je kan niet simpelweg in je programma een regel opnemen als
 
  [foo uppercaseString];

maar je zal altijd met het resultaat (een NSString *) iets moeten doen zoals bijvoorbeeld een andere string eraan laten refereren:

  NSString *bar = [foo uppercaseString];

of het opnemen in een ander statement, bijv. een logmessage

  NSLog("@Dit is foo in hoofdletters %@...", [foo uppercaseString]);


B.t.w Ik raad je aan een applicatie als AppKido (freeware) te downloaden (wel te vinden op VersionTracker). Deze Cocoa app geeft je heel makkelijk toegang tot de Cocoa API documentatie zoals op je computer aanwezig is. Dat is makkelijker dan direct de HTML te raadplegen via een browser....

groeten,
Rob