Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Objective C: How to Write a Instantiating Custom Init

Very basic question, but I have an error in my code that can only be answered by one assumption: my class isn't being instantiated!

I haven't written much in Objective C in some time, and I was never really good, so please point out even the most painfully obvious.

I am using:

ObjectSelectionViewController *length = [[ObjectSelectionViewController alloc] initWithMeasureType:0];
ObjectSelectionViewController *mass = [[ObjectSelectionViewController alloc] initWithMeasureType:1];
ObjectSelectionViewController *volume = [[ObjectSelectionViewController alloc] initWithMeasureType:2];

NSLog(@"%@", [length measurementType]);
NSLog(@"%@", [mass measurementType]);
NSLog(@"%@", [volume measurementType]);

The NSLogs return whichever measurement was assigned last, regardless of the separate allocs and inits.

Here is the constructor of the ObjectSelectionViewController class:

#import "ObjectSelectionViewController.h"

@implementation ObjectSelectionViewController

NSString *measurementType;

-(ObjectSelectionViewController*) initWithMeasureType:(int)value
{
switch (value) {
    case 0: // Length
        measureType = @"Length";
        break;

    case 1: // Mass
        measureType = @"Mass";
        break;

    case 2: // Volume
        measureType = @"Volume";
        break;
}
return self;
}

-(NSString*) measurementType
{
return measureType;
}

Thanks for the help, it's driving me crazy!

like image 715
Derek Avatar asked Jun 28 '11 22:06

Derek


2 Answers

You need to make measureType an instance variable, so that each object of this type that you create has its own copy:

@interface ObjectSelectionViewController : NSViewController {
    NSString * measureType;    // Declare an NSString instance variable
}

- (id) initWithMeasureType: (int)value;

@end

As it is, there is only one copy of the variable, and every time you instantiate a new object, its value changes. Since each instance is referring to the same copy, they all get the same value:

ObjectSelectionViewController *length = [[ObjectSelectionViewController alloc] initWithMeasureType:0];
NSLog(@"%@", [length measurementType]);     // Prints "Length"
ObjectSelectionViewController *mass = [[ObjectSelectionViewController alloc] initWithMeasureType:1];
NSLog(@"%@", [length measurementType]);    // Prints "Mass"

You also need to change your init... method as mentioned by other answerers:

- (id) initWithMeasureType: (int)value {

    // Call superclass's initializer
    self = [super init];
    if( !self ) return nil;

    switch (value) {
        case 0: // Length
            measureType = @"Length";
            break;

        case 1: // Mass
            measureType = @"Mass";
            break;

        case 2: // Volume
            measureType = @"Volume";
            break;
    }

    return self;
}

Since you are assigning a literal string to the instance variable, you do not need to worry about managing its memory; if you were doing anything more complicated, you would probably do well by declaring a property. Another note: initializer methods should always return id, a generic object pointer, to allow subclasses to work properly.

like image 128
jscs Avatar answered Oct 04 '22 17:10

jscs


You need to call [super init] first, like this:

-(id) initWithMeasureType:(int)value
{
    if ((self = [super init]))
    {
        switch (value) {
            case 0: // Length
                measureType = @"Length";
                break;

            case 1: // Mass
                measureType = @"Mass";
                break;

            case 2: // Volume
                measureType = @"Volume";
                break;
        }
    }
    return self;
}
like image 28
Hollance Avatar answered Oct 04 '22 16:10

Hollance