Как скопировать свойства суперкласса в подкласс? - PullRequest
1 голос
/ 06 февраля 2012

Допустим, у меня есть два класса, например, так:

Car
{
   NSInteger wheels;
   NSInteger bumpers;
}

+ (Car *)carWithData:(NSDictionary *)carData;


Lexus : Car
{
   GPS *navigation;
}

+ (Lexus *)carWithData:(NSDictionary *)carData;

carWithData: - это простой вспомогательный метод, который создает экземпляр Car, заполненный переменными из carData.Версия Lexus также установит данные navigation.

Как бы выглядел carWithData Lexus без дублирования кода из Car?

Ответы [ 4 ]

5 голосов
/ 06 февраля 2012

Это достигается путем вызова super реализации init… в методе init:

//Car.m:
- (id)initWithData:(NSDictionary *)carData {
    self = [super init];
    if (self) {
        //setup generic car properties:
        self.wheels = [carData objectForKey:@"wheels"]; //example
        self.bumpers = [carData objectForKey:@"bumpers"]; //example
    }
    return self;
}

+ (id)carWithData:(NSDictionary *)carData {
    return [[[self alloc] initWithData:carData] autorelease];
}


//Lexus.m:
- (id)initWithData:(NSDictionary *)carData {
    //this call to super is where the car's generic properties get initialized:
    self = [super initWithWithData:carData];
    if (self) {
        //setup lexus car properties:
        self.navigation = [carData objectForKey:@"navigation"]; //example
    }
    return self;
}

//there is no need to override super's [carWithData:] method as it's only a wrapper anyway.

Также обратите внимание, что оба метода initWith… и carWith… возвращают id,не Car или Lexus.При настройке вашего кода вы сталкиваетесь с проблемами приведения, где [Lexus carWithData:dataDict] возвращает объект класса Lexus, но компилятор не знает об этом, поскольку ожидает Car.

0 голосов
/ 20 марта 2017

Существует другой способ, который является более общим, с использованием протокола NSCoding и NSKeyedArchiver.

Если объект, который вы хотите скопировать в ваш подкласс, реализует протокол NSCoding, которыйв случае многих классов, основанных на NS ..., может быть использован следующий вполне законный и безопасный прием:

// Assumptions:
// copyFrom is an object of ClassA
// We have a ClassB that is a subclass of ClassA
NSMutableData *data = [NSMutableData data];
NSKeyedArchiver *arch = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
[copyFrom encodeWithCoder:arch]; // this archives its properties
[arch finishEncoding];
NSKeyedUnarchiver *ua = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
ClassB *ourCopy = [[ClassB alloc] initWithCoder:ua]; // this restores the properties into our new object
0 голосов
/ 06 февраля 2012

Вот мое решение:

// interface
-(id) initWithCarData:(NSDictionary *) carData;
+(Car *) carWithCarData:(NSDictionary *) carData;

// car implementation
-(id) initWithCarData:(NSDictionary *) carData
{
    if (self = [super init])
    {
          // initialize car data
    }

    return self;
}

+(Car *) carWithCarData:(NSDictionary *) carData
{
    // note that 'self' here is the current class, 
    // there is no need to overwrite this method in the subclass
    return [[self alloc] initWithCarData:carData];
}

// lexus implementation
-(id) initWithCarData:(NSDictionary *) carData
{
     // initialize the variables that the superclass recognizes
     if (self = [super initWithCarData:carData])
     {
         // initialize the lexus data
     }

     return self;
}

Итак, когда вы вызываете [Lexus carWithCarData:myData], в итоге вызывается метод Lexus init, а не Car.

0 голосов
/ 06 февраля 2012

Вы бы не определяли методы с разными сигнатурами, например:

+ (Car *)carWithData:(NSDictionary *)carData;
+ (Lexus *)carWithData:(NSDictionary *)carData;

, вместо этого следует использовать

+ (id)carWithData:(NSDictionary *)carData;

Реализация подкласса будет выглядеть как

- (id)initWithData:(NSDictionary *)carData;
{
    self = [super initWithData:carData];
    if (self) {
         _navigation = [carData valueForKey:@"navigation"];
    }
    return self;
}

+ (id)carWithData:(NSDictionary *)carData;
{
    return [[[self alloc] initWithCarData:carData] autorelease];
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...