2013-03-11 83 views
3

我的第一个问题在stackoverflow所以请温柔。我试过寻找答案,但我真的需要帮助。id类型实例变量发送消息到实例方法

的问题是与学习有关的尼尔·戈尔茨坦的Objective-C代表傻瓜

他有在Transaction.h

#import <Cocoa/Cocoa.h> 
@class Budget; 

@interface Transaction : NSObject { 

    Budget *budget; 
    double amount; 
    NSString *name; 
    id  delegate; 
} 

//some init method 

@end 

@protocol TransactionDelegate 

@required 

- (void) spend: (Transaction *) aTransaction; 

//additional optional method 

@end 

-- 

//然后在Transaction.m以下他有这个

#import "Transaction.h" 
#import "Budget.h" 

@implementation Transaction 

@synthesize budget, delegate , amount; 

- (void) spend { 

    if ([delegate respondsToSelector:@selector(spend:)]) 
    [delegate spend:self]; 
} 

- (id) initWithAmount: (double) theAmount forBudget: (Budget*) aBudget { 
    if (self = [super init]) { 
    budget = aBudget; 
    [budget retain]; 
    amount = theAmount; 
    } 
    return self; 
} 

- (void) dealloc { 

    [budget release]; 
    [super dealloc]; 
} 

@end 

我有问题了解花m Transaction.m文件中的方法

id类型实例变量是否可以在包含它的类中调用ANY方法? 我明白,respondsToSelector是一个NSObject方法,告诉编译器一个方法是否已经实现。但是,如何委托id-type调用该方法?编译器甚至不知道它是什么对象...

请帮忙!

P.S.如果任何人对良好的Objective-C书籍有任何建议,我将非常感激。我想进入iPhone开发领域,但我想我需要先掌握Objective-C的基础知识。

谢谢!

回答

2

是的,你可以发送任何消息到delegate变量,因为它的类型是id

你写这样的:

[delegate spend:self]; 

编译器开启到这一点的objc_msgSend函数的调用,就像这样:

objc_msgSend(delegate, @selector(spend:), self); 

在运行时,则objc_msgSend函数搜索的方法表对于与选择器spend:相关联的方法,其类别(及其超类)为delegate

顺便提及,我们通常声明delegate变量是这样的:

id<TransactionDelegate> delegate; 

这告知编译器,delegate将是符合TransactionDelegate协议的对象。此声明将帮助Xcode在您尝试向delegate发送消息时为您提供更好的自动完成功能。如果以这种方式声明你的setter方法或属性,编译器在编译时也会检查你是否将它设置为符合协议的对象。

+0

谢谢!哇,那是一个非常强大的功能。我的意思是我知道id类型是这个抽象对象类型,但不知道它可以调用它自己的类的方法。 – 2013-03-11 19:05:28

1

好问题。获取Obj-C和其他编译语言之间的主要区别之一。

您可以发送任何消息到您喜欢的任何Objective-C对象。消息发送将尝试由称为运行时库的库来解决,并在运行时发生。在编译时,如果你的对象类型不是通用的id,一些IDE可能会将其标记为可能的用户错误。

在运行时,运行时库将查找匹配方法,然后查看类是否有需要它的回退处理程序,并且作为最后的手段会抛出异常。用户代码可以很好地捕捉到这个异常,并将其视为正常情况。

+0

那么通常分配给委托对象的id类型是什么?这是Obj-C的标准战术/程序吗? – 2013-03-12 14:42:54