ARC语义问题与简单的协议示例?

时间:2012-08-02 10:55:50

标签: iphone objective-c xcode cocoa-touch

我刚刚尝试了一些快速测试,我有一个问题,在下面的代码中:

@protocol stuffieProtocol <NSObject>
@required 
-(void)favouiteBiscuit;
@end

// DOG & TED ARE IDENTICAL, THEY JUST LIKE DIFFERENT BISCUITS
@interface Dog : NSObject <stuffieProtocol>
@property (strong, nonatomic) NSString *name;
@end

@implementation Dog

- (id)init {
    return [self initWithName:@"Unknown"];
}

- (id)initWithName:(NSString *)name {
    self = [super init];
    if(self) {
        _name = name;
    }
    return self;
}

- (void)whoAreYou {
    NSLog(@"MY NAME IS: %@ I AM A: %@", [self name], [self class]);
}
- (void)favouiteBiscuit {
    NSLog(@"FAVOURITE BISCUIT IS: Costa Jam Biscuit");
}
@end

Dog *stuffie_001 = [[Dog alloc] initWithName:@"Dog Armstrong"];
Ted *stuffie_002 = [[Ted alloc] initWithName:@"Teddy Sullivan"];

NSArray *stuffieArray = @[stuffie_001, stuffie_002];
for(id<stuffieProtocol> eachObject in stuffieArray) {
    [eachObject whoAreYou]; // << ERROR
    [eachObject favouiteBiscuit];
}

我的问题是我收到错误"ARC Semantic Issue: No known instance method for selector 'whoAreYou'"

如果我在[eachObject whoAreYou];前加[(Dog *)eachObject whoAreYou];,那么这适用于循环的所有迭代,但这只是错误,因为数组中的所有对象都不是Dog类型

为了正确,我应该以什么为前缀?

2 个答案:

答案 0 :(得分:2)

好吧,您将eachObject声明为ID

这意味着编译器不知道它是什么类型的对象

它只知道它实现了协议stuffieProtocol,所以肯定它可以响应方法:favouiteBiscuit

但它不知道它是否可以响应方法whoAreYou

你可以做很多事情来避免这个

最简单的是:

你可以询问eachObject是否可以执行选择器whoAreYou,在这种情况下你执行那个选择器

if ([eachObject respondsToSelector:@selector(whoAreYou) ]) {
    [eachObject performSelector:@selector(whoAreYou) ];
}

这样编译器就可以避免控制eachObject是否实现了whoAreYou

方法

它将在运行时完成,所以如果在eachObject中有一个方法whoAreYou,那么ok,它将被调用

另一种方法是为ted和dog创建一个共同的超类

(例如  SuperClassOfTedAndDog <stuffieProtocol&GT; )

并声明方法whoAreYou在那个超类中,然后在你的for循环中使用那个超类而不是ID:

for(SuperClassOfTedAndDog* eachObject in stuffieArray) {
    [eachObject whoAreYou]; 
    [eachObject favouiteBiscuit];
}

答案 1 :(得分:2)

添加

-(void) whoAreYou;

到您的协议。然后编译器知道循环中的eachObject响应该方法。