0

I am working on a subclass of SKNode called UtilityNode

@implementation UtilityNode

- (id)initWithName:(NSString *)rootName {
    self = [super init];
    if(self) {
        [self setName:rootName]; // ?
    }
    return self;
}

@end

I am setting up a designated initialiser for the new node initWithName: where I am trying to initialise the name of the superclass SKNode when creating the new subclass. I was under the impression that I could just write _name = rootName; but _name was flagged as undeclared. I have got it working (as you can see above) by using [self setName:rootName]; Can anyone shine some light on this, am I doing this correctly?

CodeSmile
  • 64,284
  • 20
  • 132
  • 217
fuzzygoat
  • 26,573
  • 48
  • 165
  • 294
  • May be if you can add some method to the super class than add same method in super class e.g. initWithName and than self = [super initWithName:rootName] ? just a thought not sure – Janak Nirmal Mar 19 '14 at 13:18

1 Answers1

4

This is correct. The _name instance variable was probably declared as @private (the default for auto-synthesizing properties) and therefore it is inaccessible by subclasses.

In well-designed class hierarchies and specifically framework classes for which there is no source code available you will find most if not all instance variables inaccessible by subclasses because it hides the implementation detail and makes future changes to the base class possible. Imagine if the base class needed to verify the name property whenever it changes - if subclasses could assign directly to the ivar they would bypass the checks added to the ivar setter method.

PS: I find dot notation friendlier on the eyes:

 self.name = rootName;

UPDATE regarding the "don't send messages to self in init/dealloc" rule:

This can easily be avoided by redesigning the class to not take non-essential parameters in its init method. A cleaner version of this subclass would be:

UtilityNode* un = [UtilityNode node];
un.name = @"some name";

If the node absolutely requires the parameter to be set, warn the user via an NSAssert in the method where the name is required to be valid.

CodeSmile
  • 64,284
  • 20
  • 132
  • 217
  • what about the "rule" that says you shouldn't access `self` in any `init` methods? – Lance Mar 19 '14 at 13:24
  • Thats a good point Lance, thats why I started off down the road of trying to use _name I would guess that its ok to use self in this case. – fuzzygoat Mar 19 '14 at 13:31
  • Thank you Steffen, thats what I was thinking, but I just wanted to get some confirmation, much appreciated. – fuzzygoat Mar 19 '14 at 13:32
  • The "don't send messages to self in init" has very specific circumstances where it can have undesirable side-effects. For example it requires that the class where you access self in init has a subclass, and that subclass has overridden the message you are sending it to. As long as you don't override setName: in UtilityNode or its subclasses you needn't worry about that. OTOH framework designers do need to consider it. http://stackoverflow.com/questions/3150494/objective-c-dot-syntax-and-init/3150906#3150906 – CodeSmile Mar 19 '14 at 13:43
  • Thanks for the update Steffen, thats a good point about setting the name outside the init, thats what I am doing with other SKNodes like SKSpriteNode anyways so I will do it the way you suggest in the update. Again thanks for you time and effort. – fuzzygoat Mar 19 '14 at 13:54
  • Just one quick question, in your example: "For example it requires that the class where you access self in init has a subclass, and that subclass has overridden the message you are sending it to." So in this case the subclass version of the self message would be used rather than the superclass version as intended? – fuzzygoat Mar 19 '14 at 14:11
  • Hmmm no, if I understand correctly the subclass' overridden method (property setter) wouldn't get called, only the super class setter. Which may or may not be what you want or expect. – CodeSmile Mar 19 '14 at 15:12