目的- c将超类转换为子类



我有两个类:

  • NWStorePackage

  • NWStorePackageConsumable

NWStorePackageConsumable是NWStorePackage的一个子类(它是为非可消费内容设计的)。

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

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

+ (id) storePackageFromStorePackageDictionary: (NSDictionary *) dictionary

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

当某些操作需要一些可消费的相关内容时,我检查包类型(在NWStorePackage中定义的enum)。如果该类型被设置为可消费产品的类型,则将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;

}

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

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

…尝试找出两个类都通用的抽象方法,并在每个子类中创建特定的实现。例如:

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

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

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

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

调试问题:

您是否试图将基类的实例强制转换为子类?这是不可能的(在正常情况下-你可以做一些指针搅拌,但你不想)。您需要预先决定您的类应该是什么样的实例。基类的目的是向消费者提供一个公共接口,而不必关心为了遵守该接口而在幕后发生的事情。

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

将类构造函数改为this

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

}

和方便方法到

最新更新