2015-09-29 2 views
0

Этот вопрос касается подклассификации класса с заводским методом. Я не могу заставить подкласс работать правильно.Как я могу использовать метод Objective-C в суперклассе при создании экземпляра подкласса?

У меня есть класс автомобиля. Я хочу, чтобы он возвращал экземпляр автомобиля только, если он способен совершить поездку на указанное расстояние, учитывая также расход топлива и топливную мощность. Для этого я сделал классный (заводский) метод.

Выполняет именно то, что я хочу, когда я вызываю фабричный метод с моего контроллера представления, чтобы создать экземпляр автомобиля (код показан ниже).

@interface Car : NSObject 
@end 

@implementation Car 
- (instancetype) init 
    { return [super init]; } 

+ (Car *) carWithFuelConsumption:(double)miles_per_gallon 
         andGallonsInTank:(double)gallons 
          forTripLength:(double)miles_to_go 
{ 
if (miles_per_gallon * gallons) > miles_to_go) { 
     Car *goodCar = [[self alloc] init]; 
     return goodCar; 
} else { 
     return nil; 
} 

Теперь мне также нужны грузовики, для которых мне необходимо отслеживать их грузоподъемность. Я сделал Truck подклассом Car.

@interface Truck : Car 
@property (double) cargoCapacityLbs; 
@end 

@implementation Truck 
- (instancetype) init { 
    self = [super init]; 
    if (self) { 
    self.cargoCapacity= 2000.0; 
    } 
    return self; 
} 

На мой взгляд контроллера я могу создать экземпляр автомобиля просто отлично:

Car *car1 = [Car carWith... 20 ...5 ... 60]; //5 gallons enough for 60 miles 
Car *car2 = [Car carWith... 20 ...5 ... 90]; 
/// car2 is nil, 5 gallons NOT enough for 60 miles at 20 miles per gallon. 

Но грузовик получает меня

A) предупреждение компилятора

Truck *t1 = [Car carWith... 20 ...5 ... 60]; //5 gallons enough for 60 miles 

**incompatible pointer types assigning to Truck from Car** 

То же самое, если Я меняю автомобиль на грузовик, вот так:

Truck *truck1 = [Truck carWith... 20 ...5 ... 60]; //5 gallons enough for 60 miles 

B) и сбой при попытке получить доступ к truck1.cargoCapacityLbs

cargoCapacityLbs ..unrecognized selector sent to instance <....>** 

Я думаю, что есть что-то фундаментальное, я не понимая о подклассов. Я попытался вызвать фабричный метод непосредственно в методе инициализации грузовика, не повезло.

Я думаю о переписывании класса Car, чтобы не использовать заводской метод, но это кажется плохим, потому что тогда проверка не может быть выполнена в классе Car и должна выполняться в контроллере представления.

Любые предложения?

+0

Cast тип 'Грузовик * t1 = (Truck *) [Автомобиль carWith ... 20 ... 5 ... 60]; ' – vadian

+0

@vadian, который избавляется от предупреждения компилятора, но приложение все еще выходит из строя из-за нераспознанного селектора. –

+0

На самом деле это должно быть «Грузовик» t1 = (Грузовик *) [Грузовой автомобиль с ... 20 ... 5 ... 60]; ' – Leonardo

ответ

2

A) Ваш подход к использованию заводского метода является законным и должен работать должным образом. Чтобы избавиться от предупреждения компилятора, используйте instancetype как тип результата в объявлении метода завода:

+ (instancetype) carWithFuelConsumption:(double)miles_per_gallon 
       andGallonsInTank:(double)gallons 
        forTripLength:(double)miles_to_go; 

B) из кода выше, вы должны иметь возможность доступа cargoCapacityLbs без сбоев (возможно, вы просто неправильно имя ?). Вот код, который я использовал, и он работал должным образом:

@interface Car : NSObject 

+ (instancetype) carWithFuelConsumption:(double)miles_per_gallon 
       andGallonsInTank:(double)gallons 
        forTripLength:(double)miles_to_go; 
@end 

@implementation Car 

+ (instancetype) carWithFuelConsumption:(double)miles_per_gallon 
       andGallonsInTank:(double)gallons 
        forTripLength:(double)miles_to_go 
{ 
    if(miles_per_gallon * gallons > miles_to_go) { 
     Car *goodCar = [[self alloc] init]; 
     return goodCar; 
    } else { 
     return nil; 
    } 
} 
@end 

@interface Truck : Car 
@property double cargoCapacityLbs; 
@end 

@implementation Truck 
- (instancetype) init { 
    self = [super init]; 

    if (self) { 
     self.cargoCapacityLbs = 2000.0; 
    } 

    return self; 
} 
@end 


Truck* t1 = [Truck carWithFuelConsumption:5 andGallonsInTank:44 forTripLength:3]; 
NSLog(@"%f", t1.cargoCapacityLbs); 
+0

. Я был не очень доволен наличием Автомобиль * goodCar = [[self alloc] init]; Итак, я изменил реализацию автомобиля следующим образом: –

0

Тип объекта: Instancetype. Но я был не очень доволен наличием

Car *goodCar = [[self alloc] init]; 

в заводском методе.

я наткнулся на этом блоге http://ernstsson.net/post/80915338055/objective-c-class-factory-methods

Так что я изменил автомобиль:

@interface Car 
@property double burn; 
@property double gallons; 
@end 

@implementation Car 

- (instancetype) init { 
    return nil; 
///preclude use of an incomplete initializer 
} 

- (instancetype) initWithBurn:(double)MPG andGallonsInTank:(double) gallons { 

self = [super init]; 
if (self) { 
    _burn = MPG; 
    _gallons = gallons; 
} 
return self; 
} 

+ (instancetype) createWithFuelConsumption:(double)MPG andGallonsInTank:(double)Gallons forTripLength:(double) miles { 

if (MPG * Gallons < miles) {  
    return nil; 
} else {   
    return [[self alloc] initWithBurn:MPG andGallonsInTank:Gallons];   
} 
} 

Теперь больше нет ссылки на класс автомобиля в фабричном методе.

(не могли бы отправить это как комментарий, это слишком долго)

+0

Да, согласен; Мне тоже было неудобно иметь Car * goodCar = [[self alloc] init]; –