Deklarera en klass i XCode/Objective-C

Tråden skapades och har fått 24 svar. Det senaste inlägget skrevs .
1

Hej.

Jag sitter tappert och försöker lära mig att programmera i Objective-C tillsammans med Cocoa-frameworks.

Läser till civilingenjör vid Linköpings universitet och har där programmerat i LISP (Racket). Som projekt i min tidigare programmeringskurs byggde jag en tetrisklon.

Ett utmärkt första projekt att återskapa med Cocoa tänkte jag, men jag stöter på en hel del problem jag inte lyckas förstå. Undrar därför om det finns någon snäll och allvetande kodapa (utvecklare) som kan hjälpa mig?

Jag har skapat en klass som heter Gameboard och läst in interface-filen Gameboard.h i main.m med hjälp av:

#import "Gameboard.h"

Jag försöker sedan skapa ett objekt i main.m med hjälp av:

Gameboard * mainboard =  [[Gameboard alloc] init]

XCode säger då att Gameboard är en "Undeclared identifier". Själv tycker jag att jag klart och tydligt deklarerat klassen Gameboard i Gameboard.h (eller ja Xcode gör ju t o m detta automatiskt).

Hur gör jag för att klassen ska kunna användas?

Tack på förhand

Hur ser det ut i Gameboard.h?

Ursprungligen av Marcus K:

Hur ser det ut i Gameboard.h?

#import <Foundation/Foundation.h>
#import "Stone.h"

@interface Gameboard : NSObject {
@private
    NSMutableArray * matrix;
    
}

-(void) addStone: (Stone *) s X:(int)x Y:(int)y;

-(Stone *) getStoneX: (int) x Y: (int) y; 

-(BOOL) stoneInPosX: (int) x Y: (int) y;

-(void) removeStone:(Stone *)s X:(int)x Y:(int)y;

@end

edit: Kan lika gärna slänga med main.m också:

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


int main(int argc, char *argv[])
{
    return NSApplicationMain(argc, (const char **)argv);
    
    Gameboard * mainboard = [[Gameboard alloc] init];
    
}
Senast redigerat 2012-06-05 17:53
Ursprungligen av hansfilipelo:
#import <Cocoa/Cocoa.h>
#import "Gameboard.h"

int main(int argc, char *argv[])
{
    return NSApplicationMain(argc, (const char **)argv);
    
    Gameboard * mainboard = [[Gameboard alloc] init];
   
}

Det som kommer efter raden med "return" kommer aldrig köras (död kod).

Ursprungligen av marcushedenstrom:

Det som kommer efter raden med "return" kommer aldrig köras (död kod).

Sådär ja! Det borde jag vetat.

Tack Marcus!

edit: nope löste inte problemet... Xcode som inte hann uppdatera varningarna bara.

OffTopic: Förresten - din gamla G4 MDD rullar än, men den kommer pensioneras om någon vecka

Ursprungligen av hansfilipelo:

OffTopic: Förresten - din gamla G4 MDD rullar än, men den kommer pensioneras om någon vecka

Min MDD? O_o

Ursprungligen av marcushedenstrom:

Min MDD? O_o

Har för mig att jag köpte den av dig en gång i tiden... Eller har jag fel?

Ursprungligen av hansfilipelo:

Har för mig att jag köpte den av dig en gång i tiden... Eller har jag fel?

Jag tror tyvärr det. Jag har aldrig sålt nån MDD komplett. Dock ett chassi, ett nätagg och en processor för sig.

Men coolt att ha en MDD som fortfarande går. Måsta vara 7 år minst. Min MDD pensionerades för 2,5 år sedan och går nu inte längre att starta, misstänker PSU-fel.

Ursprungligen av marcushedenstrom:

Jag tror tyvärr det. Jag har aldrig sålt nån MDD komplett. Dock ett chassi, ett nätagg och en processor för sig.

Men coolt att ha en MDD som fortfarande går. Måsta vara 7 år minst. Min MDD pensionerades för 2,5 år sedan och går nu inte längre att starta, misstänker PSU-fel.

Sedärja. Minnet är bra men kort.

Åter till topic:

Min main.m har ni redan sett. Här kommer stone.h:

#import <Foundation/Foundation.h>
#import "main.m"

@interface Stone : NSObject {
@private
    int col;
    int row;
    
    NSString * color;
    
}

-(void) moveStoneX:(int)x Y:(int)y;

-(NSString *) getColor;

-(BOOL) checkDown;

-(BOOL) checkLeft;

-(BOOL) checkRight;

@end

Här är är stone.m:

#import "Stone.h"

@implementation Stone

//Moves the stone from one position to another on mainboard
-(void)moveStoneX:(int)x Y:(int)y {
        [mainboard addStone:self X:x Y:y];
        [mainboard removeStone:self X:col Y:row];
        col = x;
        row = y;
}

//Gets the stones color
-(NSString *)getColor {
    return color;
}

//Checks if there is a stone in the position beneth this stone
-(BOOL)checkDown {
    return [mainboard stoneInPosX: col Y: (row + 1)] ? NO : YES;
}

//Checks if there is a stone in the position to the left of this stone
-(BOOL)checkLeft {
    return [mainboard stoneInPosX:(col - 1) Y:row];
}

//Checks if there is a stone in the position to the right of this stone
-(BOOL)checkRight {
    return [mainboard stoneInPosX:(col + 1) Y:row];
}


//-------------------------------INIT---------------------------
- (id)init
{
    self = [super init];
    if (self) {
        // Initialization code here.
    }
    
    return self;
}

//-------------------------------initWithPosX:Y:---------------------------

//- (id)initWithPosX:Y: {
//    self = [super init];
//    if (self) {
//        [sideboard
//    }
//    
//    return self;
//}

//-------------------------------DEALLOC------------------------

- (void)dealloc
{
    [super dealloc];
}

@end

Bifogar en bild på felmeddelandena Xcode ger i stone.m.

Spontant så ser jag inget som ser direkt fel ut. Inkluderas Gameboard.h i main.m innan dess den används där så ska det där fungera. Får du utöver felmeddelandet något annat felmeddelande eller varning? Det skulle vara att det blir fel när Stone.h importeras. Kan för övrigt nämna att om Stone är en klass så räcker det med att deklarera den med @class i Gameboard.h, kompilatorn behöver inte känna till den mer än så och man undviker att importera mer än nödvändigt. Men givet informationen som du har gett så ser jag i alla fall inte vad problemet är.

Ursprungligen av Marcus K:

Spontant så ser jag inget som ser direkt fel ut. Inkluderas Gameboard.h i main.m innan dess den används där så ska det där fungera. Får du utöver felmeddelandet något annat felmeddelande eller varning? Det skulle vara att det blir fel när Stone.h importeras. Kan för övrigt nämna att om Stone är en klass så räcker det med att deklarera den med @class i Gameboard.h, kompilatorn behöver inte känna till den mer än så och man undviker att importera mer än nödvändigt. Men givet informationen som du har gett så ser jag i alla fall inte vad problemet är.

Problemet löste sig efter jag tagit bort #import stone.h i Gamebord.h och lagt till @class Stone;

Borde ej varit orsaken...

Jag har däremot problem med att Stone-klassen (som importerar main.m i Stone.h) ej vill kännas vid "mainboard" som en instans av Gameboard.

Om jag skriver [mainboard "metod"] i stone.m säger XCode "Unknown reciever 'mainboard': did you mean 'Gameboard'?

Ursprungligen av hansfilipelo:

Problemet löste sig efter jag tagit bort #import stone.h i Gamebord.h och lagt till @class Stone;

Borde ej varit orsaken...

Det beror på vad du gör i Stone.h. Blir det fel när preprocessorn ska importera Stone.h så kanske resten av Gameboard.h inte importeras in i main.m som den ska. Om du tar din gamla kod, öppnar main.m i Xcode och visar i preprocessat format (finns i Product-menyn) så ser du vad som skickas vidare till kompilatorn och kan se om det blir något fel i det steget.

Ursprungligen av hansfilipelo:

Jag har däremot problem med att Stone-klassen (som importerar main.m i Stone.h) ej vill kännas vid "mainboard" som en instans av Gameboard.

Om jag skriver [mainboard "metod"] i stone.m säger XCode "Unknown reciever 'mainboard': did you mean 'Gameboard'?

Till skillnad från Lisp så har Objective-C inte dynamiskt scope, så alla variabler måste vara definierade där de ska användas; antingen globalt eller lokalt.

Ursprungligen av Marcus K:

Det beror på vad du gör i Stone.h. Blir det fel när preprocessorn ska importera Stone.h så kanske resten av Gameboard.h inte importeras in i main.m som den ska. Om du tar din gamla kod, öppnar main.m i Xcode och visar i preprocessat format (finns i Product-menyn) så ser du vad som skickas vidare till kompilatorn och kan se om det blir något fel i det steget.

Till skillnad från Lisp så har Objective-C inte dynamiskt scope, så alla variabler måste vara definierade där de ska användas; antingen globalt eller lokalt.

Hittar tyvärr inget alternativ som heter något med "preprocess".

Vad är dynamiskt scope?

Hur definerar man globalt i Objective-C?

Ursprungligen av hansfilipelo:

Problemet löste sig efter jag tagit bort #import stone.h i Gamebord.h och lagt till @class Stone;

Det låter lite som en cirkelimport.

main importerar Gameboard importerar Stone importerar main (igen).

Du kan importera i implementationsfilen (.m) om du inte vill kedjeimportera på det här viset.

Jag kör @class när det blir cirkelimporter. Det betyder bara att "det finns en klass som heter xyz, men bry dig inte om vad som står i den".

Ursprungligen av hansfilipelo:

Problemet löste sig efter jag tagit bort #import stone.h i Gamebord.h och lagt till @class Stone;

Borde ej varit orsaken...

Jag har däremot problem med att Stone-klassen (som importerar main.m i Stone.h) ej vill kännas vid "mainboard" som en instans av Gameboard.

Om jag skriver [mainboard "metod"] i stone.m säger XCode "Unknown reciever 'mainboard': did you mean 'Gameboard'?

Är "metod" en statisk metod? Alltså en sån som du anropar på klassen, inte på en instans av klassen.

Statiska metoder börjar på "+",

@interface Gameboard : NSObject
- (void)myMethod;
+ (void)myStaticMethod;
@end

anropas

Gameboard gb = [[Gameboard alloc] init];
[gb myMethod];
[gb release];

[Gameboard myStaticMethod];
Ursprungligen av marcushedenstrom:

Är "metod" en statisk metod? Alltså en sån som du anropar på klassen, inte på en instans av klassen.

Statiska metoder börjar på "+",

@interface Gameboard : NSObject
- (void)myMethod;
+ (void)myStaticMethod;
@end

anropas

Gameboard gb = [[Gameboard alloc] init];
[gb myMethod];
[gb release];

[Gameboard myStaticMethod];

Metoden är en instansmetod.

- mainboard är min instans
- Gameboard är min klass

Problemet är att i stone.m så vill den inte alls kännas vid att jag deklarerat Gameboard * mainboard = [[Gameboard alloc] init]

not: (i enlighet med Obj-C guidelines definerar jag klasser med stor bokstav i början, övrigt med liten)

Ursäktar att jag är så frågvis. Tack för att du är så snäll och ger svar trots mina luddiga beskrivningar.

Deklarera en klass i XCode/Objective-C

Bästa rådet jag kan ge är att du tittar på många exempel. Gärna små enkla exempel är du iOS utvecklare finns massor av små exempel för nerladdninf finns på utvecklarsidorna.

Ursprungligen av gotfredsen:

Bästa rådet jag kan ge är att du tittar på många exempel. Gärna små enkla exempel är du iOS utvecklare finns massor av små exempel för nerladdninf finns på utvecklarsidorna.

Jag håller helt med.

Jag har läst omöjligt mycket dokumentation och kollat på flera timmar instruktionsvideo de senaste dagarna - men jag kan ändå inte se var jag gör fel.

Just nu utvecklar jag för OS X. iOS är nästa steg.

Varför importerar du main.m i Stone.h?

Ursprungligen av marcushedenstrom:

Varför importerar du main.m i Stone.h?

För att jag i main.m skapar min instans av Gameboard (mainboard) som jag vill använda i klassen "stone".

Generellt är det dåligt med globala variabler men för just min modell är spelaren och spelplanen två saker som behöver vara globalt definierade.

Hur bör jag göra?

Ursprungligen av hansfilipelo:

För att jag i main.m skapar min instans av Gameboard (mainboard) som jag vill använda i klassen "stone".

Generellt är det dåligt med globala variabler men för just min modell är spelaren och spelplanen två saker som behöver vara globalt definierade.

Hur bör jag göra?

Aha! Det är lite konstigt.

Vill du att en instans av Stone ska känna till vilket Gameboard det ligger på kan du ha ett Gameboard-attribut på Stone.

@interface Gameboard : NSObject {
    Gameboard board;
}
...
@property (assign) Gameboard *board; // Bara assign, inte retain
@end


[.m]

@implementation Gameboard

@synthesize board;
@end
Gameboard myGameboard = [[Gameboard alloc] init];
Stone *stone = [[Stone alloc] init];
stone.board = myGameboard; // Berätta för stone vilket board den sitter på
...
Ursprungligen av marcushedenstrom:

Aha! Det är lite konstigt.

Vill du att en instans av Stone ska känna till vilket Gameboard det ligger på kan du ha ett Gameboard-attribut på Stone.

@interface Gameboard : NSObject {
    Gameboard board;
}
...
@property (assign) Gameboard *board; // Bara assign, inte retain
@end


[.m]

@implementation Gameboard

@synthesize board;
@end
Gameboard myGameboard = [[Gameboard alloc] init];
Stone *stone = [[Stone alloc] init];
stone.board = myGameboard; // Berätta för stone vilket board den sitter på
...

Det jag vill åt är att alla objekt ska kunna skicka meddelanden till spelplanen - därav lösningen att definera namnet globalt. Så löste jag det i LISP/DrRacket.

De klasserna som kommer finnas utöver stenar är former (som innehåller stenar) och spelaren (som styr en form).

Är det bättre att skapa strukturen först och ha spelplanen som ett attribut i alla klasser? Känns som merjobb men man undviker förvisso globala variabler.

Nåt sånt här då. Jag vet inte vad som ska skickas vart, men eftersom alla objekt är relativt nära varandra vore det lämpligt att använda delegat-mönstret.

Gameboard kunde exempelvis vara delegat för shape, och få reda på när något händer med en shape. Rent praktiskt skickar shape ett meddelande till gameboard, med sig själv som argument.

[delegate shapeDidRotate:self];

Sen har du implementationen i Gameboard.

- (void)shapeDidRotate:(Shape *)shape {
    // do stuff
}

Tänkte mig mer en struktur som ser ut såhär:

Player skickar kommando till formen som har koll på sin nuvarande rotation, och därmed "vet" vad som ska hända näst.

Formen skickar sedan kommando till stenarna (alla former i tetris är fyra stenar) om hur de ska flytta sig i förhållande till nuvarande position.

Stenarna vet sin nuvarande position och verkställer ändringarna på spelplanen.

Får ta och kika på delegate som du nämner. Det är inget jag sett i dokumentationen än och har ingen koll på hur det fungerar.

edit: Bild upp och ner. Kopian på min Macbook är inte upp och ner.

edit2: Hjälper inte att ladda upp på nytt.

1
Bevaka tråden