开发者

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 =开发者_JS百科 @"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!


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.


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;
}


Constructors are a convention in Objective-C rather than a language feature. So, for example, there's no automatic calling of parent constructors (just like you wouldn't expect any other overridden method to call its parent implementations). Similarly, the names used for constructors are just conventions, so the compiler knows nothing of init. With that in mind, what you actually want as your constructor is:

-(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;
}

Assuming measureType is an instance variable (declared as part of the interface, generally speaking) and not a global then that should do what you want.


In your custom init method you just need to start with:

self = [super init];


- (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;

}

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜