你能在 Objective-C 中创建只在库中可见的类方法吗?

Can you create class methods in Objective-C only visible within your library?

提问人:stevendesu 提问时间:10/2/2019 最后编辑:stevendesu 更新时间:10/3/2019 访问量:51

问:

我在 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.hMonkey.h

客户端App.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

上面代码的直接问题是我的库无法编译,因为该类没有接口定义方法(由BananapeelMonkey.m)

我在这个问题的开头链接的 StackOverflow 问题建议创建第三个头文件:

BananaPrivate.h的

@interface Banana (PrivateMethods)
- (void)peel;
@end

然后我可以导入,我可以突然调用该方法。但是,这失败了,因为当我尝试导入时,我创建了一个碰撞 -- 我已经定义了导入时Monkey.mBananaPrivate.hpeelBananaPrivate.hBananaBanana.hMonkey.h

我无法从 中删除,因为其中一个方法返回了 类型的实例!Banana.hMonkey.hMonkeyBanana

我发现了一个古怪的解决方法,通过子类化,如下所示:Banana

内部Banana.h

@interface InternalBanana : Banana
- (void)peel;
@end

然后,在我可以安全地.但是,这有两个问题:Monkey.m#import "InternalBanana.h"

  1. 它仅适用于我的猴子实例化的香蕉(如果我库的用户实例化香蕉并将其传递给我的猴子,它将是香蕉而不是 InternalBanana)
  2. 我必须创建一个文件,但在此文件中我无法定义.尝试在 within 中定义将抛出一个未定义的错误,因为这是超类的私有变量。如果我在 within 中定义并且它只调用 ,那也会失败,因为没有定义方法。虽然这有效,但它确实会导致 Xcode 抛出警告,说没有方法定义(尽管有警告,它还是构建并运行)InternalBanana.mpeelpeelInternalBanana.mpeeledpeeledpeelInternalBanana.m[super peel]Bananapeelpeel

这个猴子生意的正确解决方案是什么?

Objective-C OOP 继承 superclass friend-class

评论

0赞 Macmade 10/2/2019
Objective-C 是一种动态语言。您可以在编译时实现此目的,但无法阻止在运行时调用现有选择器。所以可能不值得浪费你的时间......
2赞 Willeke 10/2/2019
该类别将方法添加到现有类中。它没有定义另一个类。我尝试了您的代码,没有看到冲突。Banana (PrivateMethods)peelBananaBanana
0赞 stevendesu 10/2/2019
@Willeke 显然,我的问题是我删除了位。事实证明,这是必需的,即使 Xcode 没有语法突出显示它、着色或似乎知道它是什么。我把它加回去,它起作用了。删除了它,错误。(PrivateMethods)
0赞 Amin Negm-Awad 10/2/2019
除此之外:毫无意义。它只限制对 var 的直接访问。但这已经仅限于实际的模块,因为你在类实现中定义了它。此外,与您的 Q 无关,在 .这总是正确的。@private-eathungry
0赞 stevendesu 10/3/2019
@AminNegm-Awad 好抓,我的简单错别字。吃完后,猴子应该不再饿:)

答: 暂无答案