Я нашел этот вопрос StackOverflow о классах друзей в Objective-C , который был похож на проблему, которую я пытаюсь решить, но не совсемтакой же. Поэтому я хотел бы расширить их пример.
Предположим, я хочу иметь возможность передать Обезьяне несколько бананов, и он сохранит массив всех своих собственных бананов. Когда я говорю ему, чтобы поесть, он ест из своего массива. Затем я могу попросить его дать мне банан наугад:
Banana.h
@interface Banana : NSObject
- (BOOL)isPeeled;
@end
Banana.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
Monkey.h
#import "Banana.h"
@interface Monkey : NSObject
- (void)give:(Banana *)aBanana;
- (void)eat;
- (Banana *)getBanana;
@end
Monkey.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
будет публичными заголовками в библиотеке, которую я распространяю. Предполагаемое использование моей библиотеки будет выглядеть примерно так:
ClientApp.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
, например, так:
InternalBanana.h
@interface InternalBanana : Banana
- (void)peel;
@end
Тогда в пределах Monkey.m
я могу безопасно #import "InternalBanana.h"
. Однако это имеет две проблемы:
- Это работает только для бананов, инстанцированных моей Обезьяной (если пользователь моей библиотеки создает экземпляр банана и передает его моей Обезьяне, это будетбанан, а не InternalBanana)
- Мне нужно создать файл
InternalBanana.m
, но в этом файле я не могу определить peel
. Попытка определить peel
в InternalBanana.m
приведет к ошибке, что peeled
не определено, так как peeled
является закрытой переменной суперкласса. Если я определю peel
в InternalBanana.m
и вызову будет [super peel]
, это также приведет к ошибке, поскольку Banana
не определяет метод peel
. Хотя этот работает , он заставляет XCode выдать предупреждение о том, что для peel
нет определения метода (но он создается и работает, несмотря на предупреждение)
Что такое собственно решение для этого обезьяньего бизнеса?