我有两个类:
-
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;
}
和方便方法到