我在 Objective-C 中的朋友类上发现了这个 StackOverflow 问题,这与我试图解决的问题相似,但并不完全相同。所以我想扩展他们的例子。
假设我想要给猴子多个香蕉的能力,他会保留一系列他自己的香蕉。当我告诉他吃饭时,他从他的阵列中吃东西。然后我可以让他随机给我一个香蕉:
香蕉.h
@interface Banana : NSObject
- (BOOL)isPeeled;
@end
香蕉.m
#import "Banana.h"
@implementation Banana
{
@private
BOOL peeled;
}
- (id)init
{
self = [super init];
if (self)
{
peeled = NO;
}
return self;
}
- (void)peel // PRIVATE METHOD
{
peeled = YES;
}
- (BOOL)isPeeled
{
return peeled;
}
@end
猴子.h
#import "Banana.h"
@interface Monkey : NSObject
- (void)give:(Banana *)aBanana;
- (void)eat;
- (Banana *)getBanana;
@end
猴子.m
#import "Monkey.h"
@implementation Monkey
{
@private
NSMutableArray *bananas;
}
- (id)init
{
self = [super init];
if (self)
{
bananas = [[NSMutableArray alloc] init];
}
return self;
}
- (void)give:(Banana *)aBanana
{
[bananas addObject:aBanana];
}
- (void)eat
{
BOOL hungry = YES;
for (int i = 0; i < bananas.count; i++)
{
if (!banana.isPeeled)
{
hungry = NO;
[banana peel];
break;
}
}
if (hungry)
{
NSLog(@"Monkey ANGRY!");
}
}
- (Banana *)getBanana
{
int r = arc4random_uniform(bananas.count);
return [bananas objectAtIndex:r];
}
@end
在这种情况下,Banana.h
并且Monkey.h
将是我正在分发的库中的公共标题。我的库的预期用途如下所示:
客户端应用程序.m
#import "MonkeyLib/MonkeyLib.h"
@implementation SomeClass
- (void)someMethod
{
Banana *oneBanana = [[Banana alloc] init];
Monkey *oneMonkey = [[Monkey alloc] init];
[oneMonkey give:oneBanana];
[oneMonkey eat];
Banana *twoBanana = [oneMonkey getBanana];
if (twoBanana.isPeeled)
{
NSLog(@"No sad monkeys!");
}
}
@end
上面代码的直接问题是我的库无法编译,因为该类的接口没有Banana
定义peel
方法(由 使用Monkey.m
)
我在这个问题开头链接的 StackOverflow 问题建议创建第三个头文件:
BananaPrivate.h
@interface Banana (PrivateMethods)
- (void)peel;
@end
然后在Monkey.m
我可以导入BananaPrivate.h
并且我可以突然调用该peel
方法。但是这失败了,因为当我尝试导入时,我创建了一个冲突——我在导入时BananaPrivate.h
已经定义了Banana
Banana.h
Monkey.h
我无法从中删除Banana.h
,Monkey.h
因为其中一种方法Monkey
返回类型的实例Banana
!
我通过这样的子分类找到了一个古怪的解决方法Banana
:
内部香蕉.h
@interface InternalBanana : Banana
- (void)peel;
@end
然后Monkey.m
我就可以安然无恙#import "InternalBanana.h"
。然而这有两个问题:
- 它仅适用于我的 Monkey实例化的 Bananas (如果我的库的用户实例化一个 Banana 并将其传递给我的 Monkey,它将是一个 Banana 而不是 InternalBanana)
- 我必须创建一个
InternalBanana.m
文件,但在这个文件中我无法定义peel
. 尝试在其中定义peel
将InternalBanana.m
引发peeled
未定义的错误,因为peeled
它是超类的私有变量。如果我在其中定义peel
并且InternalBanana.m
它只调用[super peel]
,那也将失败,因为Banana
没有定义peel
方法。虽然这可行,但它确实会导致 Xcode 抛出一个警告,指出没有方法定义peel
(但尽管有警告,它仍会构建并运行)
这个猴子生意的正确解决方案是什么?