Objective-C将超类转换为子类

时间:2014-06-30 23:48:03

标签: objective-c casting selector

我有2个班级:

  • NWStorePackage

  • NWStorePackageConsumable

NWStorePackageConsumable是NWStorePackage的子类(专为非消费内容而设计)。

我最近在项目中添加了NWStorePackageConsumable。在整个代码中我都使用NWStorePackage。

我有一个类构造函数来创建适当的实例。

+ (id) storePackageFromStorePackageDictionary: (NSDictionary *) dictionary

根据字典内容返回NWStorePackageConsumable或NWStorePackage。

当某些操作恢复某些与耗材相关的东西时,我会检查包类型(在NWStorePackage中定义的枚举)。如果该类型设置为可消费产品的类型,我将NWStorePackage实例强制转换为NWStorePackageConsumable实例并调用下面的方法。我认为铸件不会成为一个问题,因为我之前正确地制作了它们。

- (id) updateConsumableCount: (int) increase;

这会产生以下错误:

-[NWStorePackage consumableCount]: unrecognized selector sent to instance 0x9c34380

以下是调用方法

的完整代码
for(NWStorePackage *storePackage in _storePackagesArray) {
    if ([storePackage purchased]) {
        NWStorePackageStorage *sps = [NWStorePackageStorage storePackageStorageWithProductIdentifier:storePackage.productIdentifier andIsPurchased:storePackage.purchased];

        if ([storePackage packageType] == StorePackageTypeConsumable) {
            NWStorePackageConsumable *consumable = (NWStorePackageConsumable *) storePackage;
            [sps setConsumableCount: [consumable consumableCount]];
        }
        [purchases addObject:sps];
    }
}

下面的方法是NWStorePackage的构造函数,我不会在NWStorePackageConsumable中覆盖它。

+ (id) initWithContentsOfDictionary: (NSDictionary *) dictionary {
NSLog(@"Initializing NWStorePackage with dictionary content", kLOGLEVEL_STORE);

for (id key in dictionary) {
    NSLog(@"Key: %@ :: Value: %@", kLOGLEVEL_STORE, key, [dictionary objectForKey: key]);
}
NWStorePackage *package = [[NWStorePackage alloc] init];
[package setPackageID:[(NSString *)[dictionary objectForKey:@"id"] integerValue]];
[package setTitle:[dictionary objectForKey:@"title"]];
[package setProductIdentifier:[dictionary objectForKey:@"productIdentifier"]];
[package setDescriptionLong:[dictionary objectForKey:@"descriptionLong"]];
[package setDescriptionShort:[dictionary objectForKey:@"descriptionShort"]];
[package setPackageType: (StorePackageType) [[dictionary valueForKey:@"type"] longValue]];

return package;

}

2 个答案:

答案 0 :(得分:1)

一般情况下,您应该尝试替换' instanceof'具有多态性的逻辑。所以而不是:

if (myObject isKindOfClass:[NWStorePackageConsumable class])
   //doSomething
else if //etc

。 。 。尝试识别两个类共有的抽象方法,并在每个子类中创建一个特定的实现。例如:

[storePackage deliver]; //This will be different depending on consumable or not. 

如果你无法做到这一点,那么它可能表明这两个类不应该真正共享一个共同的祖先。

抽象基类vs协议与类集群:

  • 如果您有一个通用框架,请使用抽象基类,其中一些细节将由子类处理。
  • 使用您想要创建公共合同的协议,但实例之间的实现将非常不同。
  • 在您使用抽象基类的相同情况下使用类集群(抽象工厂模式的变体),并且当您还希望该公共类包含决定哪个具体实例的逻辑时在幕后返回""。

调试问题:

您是否尝试将基类的实例强制转换为子类?这是不可能的(在正常情况下 - 你可以做一些指针调整,但你不想)。你需要决定你的课程应该是前期想要的实例。基类的目的是为消费者提供一个通用接口,不必关心幕后发生的事情以符合该接口。

使用调试器,检查您的实例实际上是子类的实例。

答案 1 :(得分:0)

将类构造函数更改为此

- (id) initWithContentsOfDictionary: (NSDictionary *) dictionary {
self = [super init];

if (self) {
    NSLog(@"Initializing NWStorePackage with dictionary content", kLOGLEVEL_STORE);

    for (id key in dictionary) {
        NSLog(@"Key: %@ :: Value: %@", kLOGLEVEL_STORE, key, [dictionary objectForKey: key]);
    }

    [self setPackageID:[(NSString *)[dictionary objectForKey:@"id"] integerValue]];
    [self setTitle:[dictionary objectForKey:@"title"]];
    [self setProductIdentifier:[dictionary objectForKey:@"productIdentifier"]];
    [self setDescriptionLong:[dictionary objectForKey:@"descriptionLong"]];
    [self setDescriptionShort:[dictionary objectForKey:@"descriptionShort"]];
    [self setPackageType: (StorePackageType) [[dictionary valueForKey:@"type"] longValue]];
}

return self;

}

和便利方法