Cocoa, varför fungerar ena metoden men ej andra?

Tråden skapades och har fått 9 svar. Det senaste inlägget skrevs .
1
  • Medlem
  • Stockholm
  • 2007-04-02 20:48

Undersöker möjligheten att modifiera fönster och andra visuella klasser i Cocoa. Jag skrev en metod medan jag labbade med NSColorPanel. Den fungerar någon gång, sedan kraschar det.

- (void)awakeFromNib skapar färgpanelen, sätter MyController som target och meddelar färpanelen namnet på dess action.

- (void)actionChangeColor hämtar i båda fallen färgen från färgpanelen och ställer in bakgrundsfärgen på myWindow till den hämtade färgen.

#import "MyController.h"

@implementation MyController
- (void)awakeFromNib
{
	myColorPanel = [NSColorPanel sharedColorPanel];
	[myColorPanel setTarget:self];
	[myColorPanel setAction: NSSelectorFromString(@actionChangeColor)];
	[myColorPanel orderFront:nil];
	
}
- (void)actionChangeColor
{
	NSColor *myColor = [[NSColor alloc] init];
	myColor = [myColorPanel color];
	[myWindow setBackgroundColor: myColor];
	[myWindow display];
	[myColor release];
	
}	

@end

Cocoa har legat nere för mig ett bra tag, och jag har väl gjort något enkelt fel, för om jag snyggar upp - (void)actionChangeColor så den ser ut som den ska (?)

- (void)actionChangeColor
{
	[myWindow setBackgroundColor: [myColorPanel color]];
	[myWindow display];	
}	

Fungerar det utmärkt.

Vad har är det jag inte har förstått?

Vänligen, Ylan

I det första fallet allokerar du myColor, och gör sedan en tilldelning till myColor. När du sedan kör release på myColor försöker du släppa [myColorPanel color] istället för din allokerade NSColor...

/Erik

  • Medlem
  • Stockholm
  • 2007-04-02 21:05

Men när jag körde exakt samma metod fast kallad med en knapptryckning (IBAction), fungerade det utmärkt.

Vänligen, Ylan, som är oerhört imponerad av den snabba responsen.

Hur menar du att du gör då? Om jag lägger det du har i awakeFromNib i en IBAction kopplat till en knapp får jag samma krasch som när jag kör ditt första exempel.

  • Medlem
  • Stockholm
  • 2007-04-02 21:34
Ursprungligen av Marcus K:

Hur menar du att du gör då? Om jag lägger det du har i awakeFromNib i en IBAction kopplat till en knapp får jag samma krasch som när jag kör ditt första exempel.

Ledsen att jag var otydlig. Jag menade

- (void)actionChangeColor
{
	NSColor *myColor = [[NSColor alloc] init];
	myColor = [myColorPanel color];
	[myWindow setBackgroundColor: myColor];
	[myWindow display];
	[myColor release];
	
}	

Fast då hette den - (IBAction)changeColor

Vänligen, Ylan

Ursprungligen av Ylan:

Ledsen att jag var otydlig. Jag menade

- (void)actionChangeColor
{
	NSColor *myColor = [[NSColor alloc] init];
	myColor = [myColorPanel color];
	[myWindow setBackgroundColor: myColor];
	[myWindow display];
	[myColor release];
	
}	

Fast då hette den - (IBAction)changeColor

Det är så jag provar, men programmet byter bakgrundsfärg då jag trycker på knappen för att sedan krascha.

#import "MyController.h"

@implementation MyController
- (void)awakeFromNib
{
	myColorPanel = [NSColorPanel sharedColorPanel];
	[myColorPanel orderFront:nil];	
}
- (IBAction)changeColor:(id)sender
{
	NSColor *myColor = [[NSColor alloc] init];
	myColor = [myColorPanel color];
	[myWindow setBackgroundColor: myColor];
	[myWindow display];
	[myColor release];
}
@end
  • Medlem
  • Stockholm
  • 2007-04-02 22:47

Nu är jag med. Det visade sig att programmet inte nödvändigtvis måste krascha direkt, utan att metoden kan fungera några gånger innan det kraschar. När jag drar i punkten i färgväljaren, skickar den sin action många gånger, och jag fick intrycket av att den kraschade direkt (och jag hade inte klickat många gånger på knappen när jag testade tidigare).

Ursprungligen av Erik Aderstedt:

I det första fallet allokerar du myColor, och gör sedan en tilldelning till myColor. När du sedan kör release på myColor försöker du släppa [myColorPanel color] istället för din allokerade NSColor...
/Erik

Jag skulle helt enkelt strunta i att allokera minne för myColor? Eller dra en kopia av [myColorPanel color] och lägga på myColors allokerade minnesplats?

Då kommer ju frågan om när det blir så dyrt att sända meddelanden att det lönar sig att ha en egen kopia (om man använder informationen i en loop t. ex.)

Jag antar att man tar en egen kopia först när man märker att man har prestandaproblem.

Vänligen, Ylan

Alltså problemet är tudelat, skulle jag tro.

Dels får du ett "dött" objekt, nämligen det du allokerade och initade direkt i changeColor, och dels releasear du ett objekt du inte har retainat. [NSColorPanel color] returnerar en autoreleasead NSColor, du releasear den, sedan när autoreleasepoolen så försöker den releaseas igen. Vilket naturligtvis inte går.

Läs på om minneshantering i Cocoa. Ett bra hjälpmedel för att debugga att du releasar för mycket är NSZombie.

  • Medlem
  • Stockholm
  • 2007-04-02 23:05

Tack alla, metoden

- (IBAction)changeColor:(id)sender
{
	NSColor *myColor;
	myColor = [myColorPanel color];
	[myWindow setBackgroundColor: myColor];
	[myWindow display];
}

fungerar mycket riktigt. Min, i efterhand, solklara miss pekar på några besvärligheter kring (min?) minneshantering:
Om något fungerar när jag testat att klicka en gång, för att senare ej fungera, kan jag ej se felet. Min kod fungerade ju nyss! Sedan fungerar inte med självklarhet något många gånger, bara för att det fungerar en gång. (Jag har fortfarande inte lyckats få det att krascha med endast ett klick.)

Vänligen, Ylan

Ja, det är din minneshantering som felade

http://developer.apple.com/documentation/Cocoa/Conceptual/MemoryMgmt/index.html

Bara att läsa på

1
Bevaka tråden