Цель C: Как написать персонализированный пользовательский Init
Очень простой вопрос, но в моем коде есть ошибка, на которую может ответить только одно предположение: мой класс не создается!
Я не много писал в Objective 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 возвращаются независимо от того, какое измерение было назначено последним, независимо от отдельных распределений и inits.
Вот конструктор класса 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;
}
Спасибо за помощь, это сводит меня с ума!
Ответы
Ответ 1
Вам нужно сделать 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 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;
}
Поскольку вы назначаете литеральную строку переменной экземпляра, вам не нужно беспокоиться об управлении своей памятью; если вы делаете что-то более сложное, вы, вероятно, добьетесь успеха, объявив property.
Еще одно замечание: методы инициализации всегда должны возвращать id
, общий указатель объекта, чтобы позволить подклассам работать правильно.
Ответ 2
Сначала нужно вызвать [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;
}
Ответ 3
Конструкторы - это соглашение в 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 - это переменная экземпляра (объявленная как часть интерфейса, вообще говоря), а не глобальная, тогда она должна делать то, что вы хотите.
Ответ 4
В вашем пользовательском методе инициализации вам просто нужно начать с:
self = [super init];
Ответ 5
- (id) initWithMeasureType: (int)value {
// Call superclass 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;
}