• Apfeltalk ändert einen Teil seiner Allgemeinen Geschäftsbedingungen (AGB), das Löschen von Useraccounts betreffend.
    Näheres könnt Ihr hier nachlesen: AGB-Änderung
  • Viele hassen ihn, manche schwören auf ihn, wir aber möchten unbedingt sehen, welche Bilder Ihr vor Eurem geistigen Auge bzw. vor der Linse Eures iPhone oder iPad sehen könnt, wenn Ihr dieses Wort hört oder lest. Macht mit und beteiligt Euch an unserem Frühjahrsputz ---> Klick

Obj-C Anfängerfrage

wosinzky

Gloster
Registriert
07.02.06
Beiträge
62
Hallo Entwickler,

so langsam werde ich mit Xcode und Objective-C warm, aber die Philosophie von Obj-C, Cocoa usw. hab ich aber NOCH nicht verstanden. Da ich aber aus der C/C++ Welt komme, habe ich ein paar Verständnissprobleme. Das Buch "Programming in Objective-C" habe ich mir schon besorgt. Aber wie es immer so ist mit diesen Bücherbeispielen, sie sind immer ideal und vereinfacht gewählt (den Leser bloss nicht verwirren). D.h. auf die eigentlichen nicht trivialen Fragen bekommt man keine Antwort!

Konstruktoren/Destruktoren (ich schreibe mal K und D, das ist kürzer :) )
--------------------------------------------------------------------------
Wie bekannt ist, ist in C++ immer ein K und ein D vorhanden. Wenn keiner implementiert wird, wird halt Einer gestellt. In Obj-C gibts es keine K's bzw. D's wie in C++, stattdessen übernimmt die alloc/init-Kombination dieselbe Rolle des K (Also ein Standard der aber nicht verbindlich ist?). Hoffentlich hab ich's bis hierher richtig verstanden.
Darüber hinaus der werden in C++ die K's und D's immer ausgerufen. Ob man will oder nicht.

Wenn ich in C++ einen String in einer Methode benutzen möchte, dann schreibe ich zB. so:

int
Klasse::methode()
{
std::string aString = "blah";
}


Wenn ich die Methode verlasse, weiss ich das der String automatisch zerstört wird (der D wird aufgerufen).

Das gleiche in Obj-C müsste dann folgendermaßen aussehen:


- (int ) methode()
{
NSString *aString;

aString = [[NSString alloc] init];

}

Das Objekt aString wird aber beim verlassen der Methode nicht zerstört (is nur nen Zeiger auf ein Obj, ich weiss). Oder doch? Wie heisst in Obj-C der D? Wenn das Obj nicht zerstört wird, dann ist der Speicherbereich auf den der Zeiger zeigt verloren? Oder etwa nicht?

Ich hoffe ihr versteht mein Verständnissproblem. Wie lange lebt ein Objekt? Wie heissen den K's und D's? Und was hat es mit den autorelease-Pools aufsich?

Hoffentlich habe ich nicht zuviele Rechtschreibfehler gemacht :)

Thx
Wosinzky
 

pepi

Cellini
Registriert
03.09.05
Beiträge
8.740
In Deinem all wäre das [aString free]; allerdings hat das mit den Retain Countern von Cocoa noch nichts zu tun.
Gruß Pepi
 

Peter Maurer

Pommerscher Krummstiel
Registriert
16.03.04
Beiträge
3.077
In Deinem all wäre das [aString free]; allerdings hat das mit den Retain Countern von Cocoa noch nichts zu tun.
Gruß Pepi
NSObject kennt keine -free-Methode, soviel ich weiss. Ich glaube, Du meinst [aString release]. ;)

Und das hat was mit Retain-Countern zu tun: Die -release-Methode dekrementiert naemlich den Retain-Counter und ruft, falls letzterer bei Null angekommen ist, -dealloc auf. -autorelease dekrementiert den Counter haengend, naemlich dann, wenn der aktuelle Autorelease-Pool sein Leben aushaucht und dem Objekt die vorher beantragte -release-Botschaft sozusagen zurueckschickt (siehe die von MacApple o.g. Links), und deshalb geschieht auch alles andere dann ebenso haengend.

Jedenfalls gilt: Wer selber -dealloc aufruft (ausser natuerlich [super dealloc] in der -dealloc-Methode einer Unterklasse), der macht was falsch.
 

Yeti

Gast
int
Klasse::methode()
{
std::string aString = "blah";
}


Wenn ich die Methode verlasse, weiss ich das der String automatisch zerstört wird (der D wird aufgerufen).

Das gleiche in Obj-C müsste dann folgendermaßen aussehen:


- (int ) methode()
{
NSString *aString;

aString = [[NSString alloc] init];

}
Das wäre IMHO wohl die direkte Übersetzung in Objective-C/Cocoa:
- (int ) methode()
{
NSString *aString = @"bla";
// sollte das gleich sein wie ...= [NSString stringWithString: @"bla"];
}

(Zerstört wird aString nicht direkt beim Verlassen der Methode, sondern durch den Autoreleasepool. Wenn ich nicht ganz falsch liege.)
 

wosinzky

Gloster
Registriert
07.02.06
Beiträge
62
Moin aus dem hohen Norden,

nach den anstrengenden Christi Himmelfahrt Tagen, habe ich endlich wieder ein bisschen Zeit gefunden mich den wahren Problemen dieser Welt zu widmen ;) . Hier mein kleines Getter-Setter-Testprogramm mit dem ich so meine kleinen Verständnissprobleme habe.

Die Definition

#import <Cocoa/Cocoa.h>

@interface SetGet : NSObject {
NSString *myString;
}

- (id) init;
- (void) dealloc;
- (void) set : (NSString *) newVal;
- (NSString *) get;

@end



Die Implementation

#import "SetGet.h"

@implementation SetGet

- (id) init
{
printf("=== init ===\n");

if ((self = [super init])) // superclass may return nil
{
myString = [[NSString alloc] init];
}

return self;
};

- (void) dealloc
{
printf("=== dealloc ===\n");

[myString release];

[super dealloc];
}

- (void) set : (NSString *) newVal
{
printf("=== set ===\n");
[myString release];
myString = [newVal copy];
};

- (NSString *) get
{
printf("=== get ===\n");
return myString;
};

@end



Und einmal ausprobiert

#import "SetGet.h"
#import <Cocoa/Cocoa.h>

int main(int argc, char *argv[])
{
SetGet *myTest = [[SetGet alloc] init];

[myTest set: @"a text"];

printf("%s\n", [[myTest get] UTF8String]);

[myTest release];

return 0;
}




Die Ausgabe


[Session started]
=== init ===
=== set ===
=== get ===
Setter_Getter_Tester[313] *** _NSAutoreleaseNoPool(): Object 0x3079e0 of class NSCFData autoreleased with no pool in place - just leaking
a text
=== dealloc ===

Setter_Getter_Tester has exited with status 0.



Was will er mit seinem ARP? Ich baue doch alles ordnungsgemäss auf und ab! Oder nicht? Wo ist mein Denkfehler?

MfG
Wosinzky
 

Peter Maurer

Pommerscher Krummstiel
Registriert
16.03.04
Beiträge
3.077
Schnellschuss -- wer's besser weiss, der korrigiere mich bitte:

Du selber machst gar keinen Fehler, Wosinzky, aber Cocoa braucht nun mal zumindest einen aktiven Autorelease-Pool. Die -UTF8String-Methode aus NSString z.B. autoreleaset ihren Rueckgabewert, wie auch der Dokumentation zu entnehmen ist (Hervorhebung von mir):

The returned C string is automatically freed just as a returned object would be released; you should copy the C string if it needs to store it outside of the autorelease context in which the C string is created.
Also mach' mal einen Autorelease-Pool um Deine Anweisungen rum und guck, ob's dann geht. :)

Code:
int main(int argc, char *argv[])
{
	NSAutoreleasePool *mainAutoreleasePool = [[NSAutoreleasePool alloc] init];
	SetGet *myTest = [[SetGet alloc] init];
	[myTest set: @"a text"];
	printf("%s\n", [[myTest get] UTF8String]);
	[myTest release];
	[mainAutoreleasePool release];
	return 0;
}
Hoffentlich hab' ich mich nicht vertippt. Abgesehen davon hat Dein Code fuer mein Gefuehl ein paar Schoenheitsfehler, aber das Fass lassen wir jetzt mal zu. Wahrscheinlich ist Dir das eh selber klar.
 

MacApple

Schöner von Bath
Registriert
05.01.04
Beiträge
3.652

- (void) set : (NSString *) newVal
{
printf("=== set ===\n");
[myString release];
myString = [newVal copy];
};
Dieser Setter ist sehr gefährlich, denn wenn mal newVal == myString ist, wird newVal released, bevor es kopiert wird. Das ist gar nicht gut für die Stabilität des Programms. Abhilfe: myString ein autorelease schicken.

MacApple
 

Peter Maurer

Pommerscher Krummstiel
Registriert
16.03.04
Beiträge
3.077
Dieser Setter ist sehr gefährlich, denn wenn mal newVal == myString ist, wird newVal released, bevor es kopiert wird. Das ist gar nicht gut für die Stabilität des Programms. Abhilfe: myString ein autorelease schicken.
Das war einer der "Schoenheitsfehler", die ich gemeint hab'. :D

Und weil Setter so ein schoenes Thema sind, hier gleich noch die Variante, die ich am liebsten verwende:

Code:
- (void)setValue: (id)newValue {
	[newValue retain];
	[myValue release];
	myValue = newValue;
}
Denn merke: NSStrings sind non-mutable. In den meisten Faellen (wenn's nicht heimlich doch ein NSMutableString ist, der spaeter noch veraendert wird), reicht es also voellig aus, denselben String, der uebergeben wird, weiterzuverwenden.

Und wenn man Objekte verwendet, die das NSCopying-Protokoll nicht unterstuetzen, dann geht copy eh nicht.

Koennte uebrigens sein, dass die NSString-copy-Methode sich tatsaechlich selbst zu einer retain-Anweisung vereinfacht. Ich erinnere mich schwach, mal sowas gelesen zu haben; aber ausprobiert hab' ich's noch nie. Und es koennte auch stringWithString o.ae. betroffen haben.

Und wenn's doch kopiert werden soll, dann eben so:

Code:
- (void)setValue: (id)newValue {
	id copiedValue = [newValue copy];
	[myValue release];
	myValue = copiedValue;
}
Es bleibt natuerlich Geschmackssache; aber manchmal ist es einfach netter, nicht allzuviel Kram sich im Autorelease-Pool ansammeln zu lassen. :)
 

MacApple

Schöner von Bath
Registriert
05.01.04
Beiträge
3.652
Das war einer der "Schoenheitsfehler", die ich gemeint hab'. :D
Das stand aber noch nicht da, als ich meinen Beitrag geschrieben habe. ;)

Denn merke: NSStrings sind non-mutable. In den meisten Faellen (wenn's nicht heimlich doch ein NSMutableString ist, der spaeter noch veraendert wird)
Eben weil man dem Setter auch einen NSMutableString übergeben darf, muss man sich darüber im klaren sein, was das für Konsequenzen haben kann.

Und wenn man Objekte verwendet, die das NSCopying-Protokoll nicht unterstuetzen, dann geht copy eh nicht.
Logisch.

Koennte uebrigens sein, dass die NSString-copy-Methode sich tatsaechlich selbst zu einer retain-Anweisung vereinfacht. Ich erinnere mich schwach, mal sowas gelesen zu haben; aber ausprobiert hab' ich's noch nie. Und es koennte auch stringWithString o.ae. betroffen haben.
Ja, NSString ist ja ein Class-Cluster, besteht also eigentlich aus diversen anderen Klassen, die dann jeweils optimierte Methoden haben.

Es bleibt natuerlich Geschmackssache;
Wie ich einen Setter implementiere sollte keine Geschmacksfrage sein, sondern sich am erwarteten Verhalten orientieren.

MacApple