目标C:如何编写实例化自定义初始化



这是一个非常基本的问题,但我的代码中有一个错误,只能通过一个假设来回答:我的类没有被实例化!

我已经有一段时间没有写太多关于目标C的文章了,而且我从来都不是很好,所以请指出哪怕是最明显的。

我正在使用:

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]);

NSLogs返回最后分配的度量值,而不考虑单独的alloc和init。

以下是ObjectSelectionViewController类的构造函数:

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

谢谢你的帮助,我快疯了!

您需要使measureType成为实例变量,这样您创建的每个此类对象都有自己的副本:

@interface ObjectSelectionViewController : NSViewController {
    NSString * measureType;    // Declare an NSString instance variable
}
- (id) initWithMeasureType: (int)value;
@end

实际上,变量只有一个副本,每次实例化一个新对象时,其值都会发生变化。由于每个实例都引用相同的副本,因此它们都获得相同的值:

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

你还需要改变你的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;
}

由于您正在为实例变量分配一个文本字符串,因此不需要担心管理它的内存;如果你在做更复杂的事情,你可能会通过声明一个财产来做得很好。另一个注意事项是:初始化器方法应该始终返回id,一个通用对象指针,以允许子类正常工作。

您需要首先调用[super init],如下所示:

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

构造函数是Objective-C中的约定,而不是语言特性。因此,例如,不存在对父构造函数的自动调用(就像您不希望任何其他重写方法调用其父实现一样)。类似地,用于构造函数的名称只是约定,所以编译器对init一无所知。考虑到这一点,你真正想要的构造函数是:

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

假设measureType是一个实例变量(一般来说,作为接口的一部分声明),而不是全局变量,那么这应该符合您的要求。

在您的自定义init方法中,您只需要从开始

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;

}

最新更新