Einstieg für Delphi-Programmierer/kompletten Neuling?

S

sECuRE

Aktives Mitglied
Thread Starter
Dabei seit
25.06.2005
Beiträge
568
Reaktionspunkte
6
Hi,

ich habe mir jetzt XCode von der Apple Homepage besorgt und trotz erst 3 Tagen Mac-Vergnügen würde ich gerne in's Programmieren einsteigen auf einem Mac. Ich kenn von Windows her Delphi, von Linux C++ (nur auf Kommandozeilenebene), insofern habe ich keine großen Schwierigkeiten mit dem Objective-C-Code. Was mir einiges an Kopfzerbrechen bereitet ist die XCode-IDE und das Denken hinter dem Interface Builder/dessen Komponenten.

Wie ich eine "einfache" NSTableView mit Daten fülle über Sourcecode scheint schon ein sehr komplexes Thema zu sein. Unter Delphi ging das mit "ListView.Items.Add('test');", hier muss ich erst einen NSArrayController erstellen, den dann irgendwie mit Bindings und sonstwas anpassen, eigene Methoden zum Objektzurückgeben definieren... *bin total verwirrt*.

Hat jemand da vielleicht eine einfache Erklärung/ein einfaches Tutorial dazu? Möglichst bebildert und auf deutsch? ;)
Google recherchen finden meistens englische Seiten (was heißt meistens :rolleyes: ), die Apple-Dokumentation finde ich sehr theoretisch, sie hat kaum Anwendungsbeispiele.

Als Projekt habe ich mir eine kleine Steuerung vorgenommen, welche aus einer Datei Daten ausliest und anzeigt, später soll das ganze auf Sockets erweitert werden, per Telnet sollen dann Befehle abgearbeitet werden (auf Serverseite, mein Programm sendet nur die Befehle und gibt die Ausgabe grafisch aus). Damit habe ich wohl erstmal 'ne Weile zu tun...

Vielen Dank im Voraus,
cu
 
Der IB ist tatsächlich zunächst gewöhnungsbedürftig, hat man sich aber erst einmal eingearbeitet, sehr effizient.
Zu deiner Frage mit dem NSTableView: Ein NSTableView speichert keine Daten, wie es beispielsweise eine Listenansicht unter Windows mit Delphi, VB, VC++, usw. tut. Es ist sozusagen nur eine Maske – Die Daten mußt du selbst durch die Instanz einer Klasse die einem bestimmten Protokoll (Objective-C-Fachsprache) entsprechen muß.

Ich kann dir folgende Seiten ans Herz legen, weil es dort auch Tutorials zum NSTableView gibt:
http://www.macentwicklerwelt.net/
http://www.cocoabuilder.com/
http://cocoadevcentral.com/
http://www.cocoadev.com/
 
Bevor man mit Cocoa anfängt sollte man sich das Model-View-Controller-Prinzip angucken.

D.h. erst mal in seiner bekannten Umgebung (Delphi, C++) versuchen eine Anwendung nach diesem Prinzip aufzubauen.

Bei Delphi kann das schon schwerer werden, da es doch nach einem anderen Prinzip arbeitet. C++ sollte da als Terminal-Anwendung schon leichter sein.
 
Hi,

das Modell hab' ich mir angesehen, ich habe das so verstanden, dass man immer eine "View"-Komponenten hat, die über den Controller mit den eigentlichen Daten kommuniziert.

An der praktischen Ausführung hapert's bei mir allerdings gewaltig. Ich weiß nicht, welche Datenstruktur ich wofür nehmen muss und wohin damit?!

Mein Ansatz ist es, einen NSArrayController zu benutzen, dem gebe ich dann die Keys Number und Value, die ich vorher so festgelegt habe:
@interface MyDataClass {
int Number;
NSString *Value;
}
@end
Diese Ordne ich dann auch den Columns des NSTableView zu, soweit so gut. Danach stelle ich das Binding zwischen NSTableView und NSArrayController her. Ich "connect"e delegation und dataSource. Jetzt werde ich unsicher: Die content-eigenschaft zuweisen von NSArrayController? Aber auf was? Muss ich dazu vorher nicht ein NSArray anlegen? Aber die haben ja keinen Typ, wie kann ich dem dann deutlich machen, dass es sich hier um ein Array vom Typ MyDataClass handelt, welches ich danach nutzen will?

Ziel ist einfach, eine Liste, Array, Dictionary - ganz egal - zu haben, welches ich zur Laufzeit im Code verändern kann und das dann in dem NSTableView dargestellt wird.

Fragen über fragen. Ich hoffe jemand erbarmt sich, mir das Schritt für Schritt zu erklären, ich finde den Einstieg echt schwierig.

Vielen Dank schon mal,
cu
 
Im Prinzip funktioniert das Ganze mit dem NSTableView so, daß du deine Daten in einer eigenen Klasse speicherst und der NSTableView dann über einen Selector diese Daten abfragt:

(Pseudo-Code)
@interface MeineDatenquelle
{
NSArray *mDaten;
}

@implementation
{

- (id)objektFuerZeile: … undSpalte: …
{
return dasObjektAus_mDaten;
}

}
 
Hi,

ja, soweit war ich ja auch. Nur, brauch ich von meinem Typ jetzt eine Instanz oder wird automatisch eine erzeugt? Was genau gebe ich beim NSArrayController ein?

Edit: Ich hab jetzt mal folgenden Code ganz ohne Controller auf die Beine gestellt, nur um mal etwas funktionierendes hinzubekommen (Erfolgserlebnisse sind wichtig, wisst ihr ja :D):
MyObject.h schrieb:
/* MyObject */

#import <Cocoa/Cocoa.h>

@interface MyObject : NSObject
{
IBOutlet NSTableView *table;
NSArray *array;
}
- (IBAction)ListeFuellen:(id)sender;
@end

@interface dataSrc:NSObject
{
NSArray *array;
}
- (int)numberOfRowsInTableView:(NSTableView *)tableView;
- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)col row:(int)row;
-(void)blah;
@end

MyObject.m schrieb:
#import "MyObject.h"

@implementation dataSrc
- (int)numberOfRowsInTableView:(NSTableView *)tableView { return [array count]; }

- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)col row:(int)row {
printf("get value for row %d\n",row);
return [array objectAtIndex:row];

}
-(void)blah {
printf("ok, i'm filling in some values\n");
if (array == NULL)
array = [NSArray arrayWithObjects: @"lalelu",nil];
printf("OK,a rray size is now %d\n",[array count]);
}
@end

dataSrc *DS;

@implementation MyObject

- (IBAction)ListeFuellen:(id)sender
{
printf("Button gedrückt\n");
printf("elemente: %d\n",[table count]);
if (DS == NULL) {
printf("have to build new DS\n");
DS = [dataSrc new];
}
printf("DS ok\n");
[DS blah];
[table setDataSource:DS];
[table reloadData];
}

@end

table ist mein Outlet, was mit einem NSTableView verknüpft ist. Leider erscheint kein Eintrag ("lalelu" müsste ja erscheinen?) in der Liste. Hier die Logausgabe:

Log schrieb:
[Session started at 2005-06-28 21:09:45 +0200.]
Button gedr\237ckt
elemente: 0
have to build new DS
DS ok
ok, i'm filling in some values
OK,a rray size is now 1

Versuch-1 has exited with status 0.

cu
 
Zuletzt bearbeitet:
Bin gerade auch von Delphi auf Cocoa umgestiegen und hatte zu Beginn ähnliche Probleme. Ich kann folgendes empfehlen:

"Cocoa Programming For Mac OS X" von Aaron Hillegass. Steht alles drin, was man für den Ein-/Umstieg braucht.

Dieser NSTableView ist genial, zu Beginn viel umständlicher als in Delphi, dann aber durch die Unabhängigkeit der eigenen Datenspeicherung viel mächtiger und allgemeiner. Dagegen wirkt der TableView von Delphi geradezu archaisch. (Obwohl ich Delphi auch oft genug vermisse).

1) Du bastelst Dir Deinen NSTableView im Interface Designer. Die Methode "Delegate" muß auf Deine Controller-Instanz zeigen.

2) Du erstellst Deine Datenquelle, z.B. einen NSArray oder - falls der noch verändert werden muß - einen NSMutableArray. Das geht ähnlich wie in Delphi, zu Testzwecken:

meinArray = [[NSArray alloc] arrayWithObjects:mad:"item1",@"item2",nil];

3) im Controller müssen fürs Auslesen die Methoden

-(int)numberOfRowsInTableView:(NSTable *)atableView
{
return [meinArray count];
}

und

-(id)tableView:(NSTableView *)atableView
objectValueForTableColumn:(NSTableColumn *)aTableColumn
row:(int)rowIndex;
{
return [meinArray objectAtIndex:rowIndex];
}

gesetzt sein und ggf. fürs Editieren der Daten (dann aber NSMutableArray als Quelle!) noch

-(void)tableView:(NSTableView *)aTableView
setObjectValue:(id)anObject
forTableColumn:(NSTableColumn *)aTableColumn
row:(int)rowIndex;
{
...
}

Im Interface Designer können den Columns auch Identifier zugeordnet werden. Bei mehreren NSTableViews, die von einem Controller verarbeitet werden, müssen diese eben vorher abgefragt werden.

Hoffentlich klappt's, Gruß.
 
Mist, die blöden Männchen sind eigentlich Doppelpunkte und Klammer auf. Wie blöd...
 
Hi,

das nächste mal "grafische Smilies deaktiveren" ankreuzen ;).
Ansonsten danke für den vielen Code, das ist _in etwa_ das, was ich oben gepostet hab/vorher mal hatte. Nur noch eine kleine Frage:
im Controller müssen fürs Auslesen die Methoden[...]gesetzt sein
Und wo setze ich das? Das ist leider nicht so klar strukturiert wie in Delphi - jedes mal, wenn ich das eine Objekt ins andere "ctrl-dragge" kommen neue Eigenschaften, Methoden, Zeugs.. verwirrend.

Danke & cu
 
Du doppelklickst auf Deinen TableView im Interface Designer, nachdem Du unter "Tools" den Inspektor geöffnet hast. Du ctrl-ziehst eine Verbindung zwischen dem TableView und Deinem - hoffentlich bereits instanziierten (???) - MyObject. Im Inspektor verbindest Du dataSource (hatte ich eben vergessen!) und delegate durch Drücken des Knopfes "Connect".

Gruß.
 
oh, und nun zu Deiner eigentlichen Frage:

die Auslesemethoden des tableView würde ich in MyObject einfügen. Das Erstellen der Datenquelle kann dann in die Methode init von MyObject oder in awakeFromNib.
 
Hi,

hab alles so gemacht, wie du's geschildert hast. Leider funktioniert es noch immer nicht. Ich leg mich erst mal schlafen und dann sehen wir morgen weiter; ich freue mich über Antworten.
MyObject.m schrieb:
#import "MyObject.h"



@implementation MyObject

- (IBAction)ListeFuellen:(id)sender
{
printf("Button gedrückt\n");
printf("elemente: %d\n",[table count]);
[self blah];
printf("array count: %d\n",[array count]);
[table reloadData];
printf("DS ok\n");
}
- (int)numberOfRowsInTableView:(NSTableView *)tableView { return [array count]; }

- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)col row:(int)row {
printf("get value for row %d\n",row);
return [array objectAtIndex:row];

}
-(void)blah {
printf("ok, i'm filling in some values\n");
if (array == NULL)
array = [NSArray arrayWithObjects: @"lalelu",nil];
printf("OK,a rray size is now %d\n",[array count]);
}
-(void)init {
[self blah];
}
@end
MyObject.h schrieb:
/* MyObject */

#import <Cocoa/Cocoa.h>

@interface MyObject : NSObject
{
IBOutlet NSTableView *table;
NSArray *array;
}
- (IBAction)ListeFuellen:(id)sender;
- (int)numberOfRowsInTableView:(NSTableView *)tableView;
- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)col row:(int)row;
-(void)blah;
-(void)init;
@end
Log schrieb:
ok, i'm filling in some values
OK,a rray size is now 1

Versuch-1 has exited due to signal 10 (SIGBUS).

cu
 
Nur als Hinweiß.

Du kannst auch NSLog benutzen, anstatt printf. Das ist "ObjC-licher". ;)

Also praktisch printf durch NSLog ersetzen:

anstatt: printf("elemente: %d\n",[table count]);
einfach: NSLog(@"elemente: %d\n",[table count]); (bin mir jetzt gerade nicht sicher wegen dem "@")

;)
 
Zuletzt bearbeitet:
MyObject.h:

/* MyObject */

#import <Cocoa/Cocoa.h>

@interface MyObject : NSObject
{
NSArray *myArray;
}
@end


MyObject.m:

#import "MyObject.h"

@implementation MyObject

-(int)numberOfRowsInTableView:(NSTableView *)aTableView
{
return [myArray count];
}

-(id)tableView:(NSTableView *)aTableView
objectValueForTableColumn:(NSTableColumn *)aTableColumn
row:(int)rowIndex;
{
return [myArray objectAtIndex:rowIndex];
}

-(void)awakeFromNib
{
myArray = [NSArray arrayWithObjects:mad:"item1",@"item2",nil];
[myArray retain];
}

@end


Verbunden sein muß "delegate" und "dataSource". Funktioniert bei mir prima! Schlaf gut...
 
Hi,

in der Tat, wenn ich statt im Init im awakeFromNib das Array initialisiere, funktioniert es :). Außerdem wusste ich nicht, dass man Retain aufrufen muss nachdem man ein Array mit Objekten initialisiert. Das ist dazu da, um das abschließende Nil-Objekt wieder zu entfernen, richtig?

cu
 
Hat hier schon jemand den Namen Aron Hillegas eingeworfen? Der erklärt das alles (auch mit einem NSArrayController) recht gut. Ich hab leider zu wenig Zeit um mich da richtig reinzuarbeiten. Aber selbst als sporadisch Lernender kommt man damit gut voran.
Es steckt halt mehr dahinter als nur ne neue Sprache, es ist eine andere "Denke", die man erstmal inhalieren muß...
 
Hi,

der scheint ja das nonplusultra-Buch geschrieben zu haben (die Kurse kommen überhaupt nicht in Frage, sind viel zu teuer. Ich mach das ja nur als Hobby.). Trotzdem würde ich gerne alle nötigen Informationen aus dem Web holen. Leider sieht es mit deutschen Mac-Entwickler-Tutorials ja ziemlich mau aus :(

cu
 
retain hat mit dem letzten nil nichts zu tun. retain sorgt dafür, daß der "zähler" des array um eins erhöht wird und der array am ende der prozedur nicht entfernt wird. man sollte ihn vorm beenden wieder mit release freigeben.
 
Hi,

retain reserviert also den Speicher und gibt das Objekt nicht frei beim Beenden der aktiven Funktion/Prozedur/wasauchimmer. Aber das mit dem Zähler habe ich nicht verstanden?

cu
 
nein. retain reserviert keinen speicher, das macht alloc. ein objekt hat so eine art internen zähler. gibst du das objekt frei und der zähler ist null, wird das objekt entfernt. ist der zähler aber ungleich null, wird so lange gewartet, bis der zähler null ist. viele add-routinen erhöhen automatisch solche zähler. zähler ist natürlich nicht das richtige wort, aber ich bin nicht profi genug, um mit den korrekten vokabeln um mich zu schmeißen. beispiel:

du erschaffst ein objekt mit alloc und init. der zähler ist dann 1. du fügst dieses objekt einem anderen zu mit einer add-routine, dadurch wird der zähler auf 2 gesetzt. machst du jetzt selbst ein release (freigabe des speichers), wird der zähler um 1 verkleinert, also auf 1 gesetzt. da dies ungleich null ist, wird das objekt gar nicht freigegeben. sobald das übergeordnete objekt, dem du deins hinzugefügt hast, aber zerstört wird, sendet dies an alle seine unterobjekte ein release. dann ist der zähler null und das objekt wird freigegeben. verstanden? vermutlich wurde diese thamtik selten so blöde beschrieben wie von mir gerade.

besser: google mal nach release, retain und cocoa.

gruß.
 
Zurück
Oben Unten