Silver Challenge Error


#1

Hey Guys!

I’m a little confused about an error I’m getting with my Silver Challenge Initialiser - perhaps it’s not the initialiser, but rather the code that I’m calling the `silverChallenge’ object with.

Here’s the thing:
BNRItem.h

- (id) initWithItemName:(NSString *)name
         valueInDollars:(int)value
           serialNumber:(NSString *)sNumber;

// Silver Challenge
- (id) initWithItemName:(NSString *)name
           serialNumber:(NSString *)sNumber;

BNRItem.m


- (id) initWithItemName:(NSString *)name
         valueInDollars:(int)value
           serialNumber:(NSString *)sNumber
{
    self = [super init];
    
    if (self) {
        [self setItemName:name];
        [self setSerialNumber:sNumber];
        [self setValueInDollars:value];
        dateCreated = [[NSDate alloc] init];
    }
    
    return self;
}
// Silver Challenge
- (id) initWithItemName:(NSString *)name
           serialNumber:(NSString *)sNumber
{
    return [self initWithItemName:name
                     serialNumber:sNumber];
}

… aaaaaaand here’s how I’m calling it in main.m:


BNRItem *silverChallenge = [[BNRItem alloc] initWithItemName:@"Thingo" serialNumber:@"1337"];
        
        NSLog(@"%@", silverChallenge);

and when I run it, I’m getting a Thread 1: EXC_BAD_ACCESS (code=2, address = 0x7fff5f3fffe8) error. This is pointing at the //Silver Challenge init that is in BNRItem.m

Can anyone detect something that I’ve done wrong? I thought I called it OK, but it seems to be not making the object…

Cheers,
Michael


#2

hmmm… SO i went back and change the code in BNRItem.m to

[code]// Silver Challenge

  • (id) initWithItemName:(NSString *)name
    serialNumber:(NSString *)sNumber
    {
    return [self initWithItemName:name
    valueInDollars:0 // THIS IS THE PART I JUST ADDED!
    serialNumber:sNumber];
    }
    [/code]
    … and it worked. I thought that I wouldn’t need to assign a valueInDollars because it wasn’t called for? Did my program crash for this reason? I thought It would just assign null or something. or nil. I forget.

Did I just make an initializer that doesn’t really do anything, because I need it to run the designated intializer which populates it with all the properties anyway?


#3

For every class you create and assign what is referred to as the the designated initializer for that class. Every other initializer that you then create in that class needs to call the designated initializer. If you’ll notice, only the designated initializer calls [super init].

So when you added the valueInDollars portion, that was actually in turn now calling your designated initializer:
-(id)initwithItemName:valueInDollars:serialNumber:

and hence initializing correctly.

Make sense?


#4

I can understand the logic, I just thought that the method would set valueInDollars to nil by default. So, I have to set a value inside the initialisation method? Damn.


#5

It’s not that you have to initialize the variable as much as you have to call the right method. If you look at this:

- (id) initWithItemName:(NSString *)name
           serialNumber:(NSString *)sNumber
{
    return [self initWithItemName:name
                     serialNumber:sNumber];
}

when you call it via:

BNRItem *p = [[BNRItem alloc] initWithItemName:@"Sexy Silver" serialNumber@"R2D2A"];

What is happening is that you’re calling an infinite loop till the app crashes out of it.

In a normal init method, primitive instance variables are set to nil.


#6

Why is there an infinite loop? Is it because it’s waiting for the valueInDollars parameter and it never gets assigned?


#7

The instance method is:

- (id) initWithItemName:(NSString *)name serialNumber:(NSString *)sNumber

Or the shorthand would be: - initWithItemName:serialNumber:

and the code in this method calls itself: return [self initWithItemName:name serialNumber:sNumber];

return [self initWithItemName:name serialNumber:sNumber];

When you have the code as:

return [self initWithItemName:name valueInDollars:0 serialNumber:sNumber]

You are actually calling the default initializer (method) -initWithItemName:valueInDollars:serialNumber which then takes the variables you passed and runs all this code:

- (id) initWithItemName:(NSString *)name
         valueInDollars:(int)value
           serialNumber:(NSString *)sNumber
{
    self = [super init];
    
    if (self) {
        [self setItemName:name];
        [self setSerialNumber:sNumber];
        [self setValueInDollars:value];
        dateCreated = [[NSDate alloc] init];
    }
    
    return self;
}

To try and make it painfully clear, what you’re doing is almost like:

- (id) init
{
   return [self init]
}

And I should clarify it’s a recursive loop that keeps calling itself till it explodes. That help clear things up?