Designated initializer - Objective-C

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

Hej,

har fastnat rejält på uppgift nr 2 i kapitel 10 i boken Programming in Objective-C(Stephen Kochan).

Förstår inte riktigt vad han menar med följande:

Given that you label the method developed in exercise 1 the designated initializer for the Rectangle class, and based on the Square and Rectangle class definitions from Chapter 8, add an initializer method to the Square class according to the following declaration:

-(Square *) initWithSide: (int) side;

Vad menar han med "Given that you label the method..." hur då? Är det den metoden som anropar

[super init]

?

Tycker hela uppgiften är luddig, jag fixar att lägga till metoden och skriva koden men jag vet ju inte om jag gör fel. Jag har skrivit följande:

-(Square *) initWithSide: (int) side
{
	self = [super init];
	
	if (self)
		[self setSide: side];
		
	return self;
}

Hittade följande hos Apple om The Designated Initializer:

The designated initializer is the method in each class that guarantees inherited instance variables are initialized(by sending a message to

super

to perform an inherited method). It's also the method that does most of the work, and the one that other initialization methods in the same class invoke.

Hur gör man detta? Tycker det verkar krångligt som satan... speciellt då om man inte har
något speciellt man vill ändra på, så måste man ändå anropa den init... som tar flest argument?

Ah jag vete fan jag är trött i skallen nu har försökt att få klarhet i detta dom senaste två dygnen och desto mer jag läser runt på nätet desto luddigare blir det.

Hjäääälp!

  • Oregistrerad
  • 2006-04-03 21:33

Den här artikleln fick mig att förstå konceptet med designated initializer:

http://www.stepwise.com/Articles/Technical/2002-10-13.01.html

Ursprungligen av David Sinclair:

The designated initializer is the method in each class that guarantees inherited instance variables are initialized.

Förmodligen har du någon initializer i din superklass som ställer in några variabler för instansen? Typ initWithWidth:height:? Den initializer som ställer in alla variabler som krävs är din designated initializer. Denna ska du använda i början av initializern till din nya klass för att vara säker på att rektangel-delen av ditt objekt är OK.

Med din kod ovan kan det mycket väl finnas odefinierade instansvariabler i rektangel-delen av din instans, eftersom du bara anropar [super init]. Den sistnämnda är designated initializer för NSObject, så om din rektangel-klass i sin tur ärver från NSObject så ska du i din initializer för rektangeln anropa just [super init].

Ursprungligen av David Sinclair:

...Vad menar han med "Given that you label the method..." hur då?...

Som framgår av artikeln joakimk länkade till så går det inte att kodmässigt styra vilken init-metod som är "Designated". Så vad han menar är att du helt enkelt lägger till em kommentar före metoden som talar om att detta .

// This is the designated init-method
-(Square *)initWithSide:(int)side {
...
Ursprungligen av David Sinclair:

Hur gör man detta? Tycker det verkar krångligt som satan... speciellt då om man inte har
något speciellt man vill ändra på, så måste man ändå anropa den init... som tar flest argument?

Egentligen är det inte så krångligt men exemplet han använder kanske inte är det bästa. Tanken är helt enkelt att du ska ha en init-metod i din klass som ser till att alla attribut får ett värde, antingen via parametrar eller som default värden.

Detta gör det enklare för dig som programmera när du sedan ska använda klassen i din övriga kod för du vet att ingen variabel är oinitierad.

Sedan kan du skapa andra init-metoder som tar färre eller andra argument men om dessa metoder alla anropar den designerade (eller vad det heter på svenska, tillägnade?) så är du garanterad att attributen blir satta.

För att fortsätta på emeplet med Square så skulle du kunna ha en init metod som heter initEmtpySquare för att skapa en tom kvadrat:

-(Square *)initEmptySquare {
  return [self initWithSide:0];
]

Det här blir enklare att förstå nyttan med när du jobbar med lite mer komplicerade klasser och framförallt har attribut som är klassr. Men som en aptitretare kan jag säga att det förenklar mycket om man har ett attribut av typ NSMutableArray (eller likande) och vet att denna array alltid är initierad så man inte måste kolla det i koden varje gång man vill lägga till ett nytt element i array:en.

Joakim

OK, får börja med att tacka för alla inlägg, har börjat förstå det hela någotsånär nu... Här är en lösning som jag tror är nära, bare with me det blir en hel del kod nu, får dock följande varning under kompilering:

paqua:~/Programming/exercise10-2 sinclair$ gcc -Wall Rectangle.m Square.m main.m -o exercise10-2 -l objc
Square.m: In function '-[Square initWithSide:]':
Square.m:16: warning: assignment from distinct Objective-C type

Rectangle.m:

#import "Rectangle.h"

@implementation Rectangle;
-(void) setWdith: (int) w
{
	width = w;
}

-(void) setWidth: (int) w
{
	width = w;
}

-(void) setHeight: (int) h
{
	height = h;
}

-(void) setWidth: (int) w andHeight: (int) h
{
	width = w;
	height = h;
}

-(int) width
{
	return width;
}

-(int) height
{
	return height;
}

-(int) area
{
	return width * height;
}

-(int) perimeter
{
	return (width + height) * 2;
}

-(Rectangle *) initWithWidth: (int) w andHeight: (int) h
{
	self = [super init];
	
	if (self)
		[self setWidth: w andHeight: h];
		
	return self;
}

@end

Square.m:

#import "Square.h"

@implementation Square: Rectangle;
-(void) setSide: (int) s
{
	[self setWidth: s andHeight:];
}

-(int) side
{
	return width;
}

-(Square *) initWithSide: (int) side
{
	self = [super initWithWidth: 0="0" andHeight: side];
	
	if (self)
		[self setSide: side];
		
	return self;
}

@end

Varningen jag får är tydligen för att jag returnerar ett Rectangle object, så hela grejen är kanske fel?

self = [super initWithWidth: 0="0" andHeight: side];

self är en Square *, superimplementationen av initWithWidth:andHeight: returnerar en Rectangle *. Kompilatorn varnar för att en Rectangle inte är en Square (det omvända är dock sant). Ändra dina initmetoder att returnera objekt av typen id, istället för de explicita typerna, så slipper du varningen.

  • Medlem
  • Mölndal
  • 2006-04-06 17:08

'to designate' betyder ju 'att tilldela/utnämna', men det blir änna svårt att få till nåt bra. Eller så är det bara för att t ex 'tilldelad initiator' känns så ovant. (i den mån nu 'initiator/initierare' ens är särskilt svenskt.)

  • Medlem
  • Simrishamn
  • 2006-04-27 20:43

Utan att ha läst igenom vad ni andra har svarat särskilt väl:
Är inte poängen med Designated Initializer att den init-metod som tar flest argument ska sköta initaliseringen, för att andra init-metoder inte ska låta bli att sätta ett default-värde till nödvändiga instansvariabler?

t.ex.:

@interface HPPerson : NSObject 
{
    NSString *name;
    NSNumber *numberOfPets;
}
- (id)initWithName:(NSString *)aName andNumberOfPets:(NSNumber *)nop;
@end

@implementation

- (id)init
{
    return [self initWithName:@"" andNumberOfPets:[NSNumber numberWithInt:0]];
}

- (id)initWithName:(NSString *)aName andNumberOfPets:(NSNumber *)nop
{
    self = [super init];
    numberOfPets = [nop retain];
    name = [aName retain];
    return self;
}
@end

Tror det är något sånt iaf. Säkert fullt med fel, jag är lite halvrostig med min ObjC.

1
Bevaka tråden