关于stackoverflow的第一个问题所以请保持温和。我试过寻找答案,但我真的需要帮助。
问题在于了解Neal Goldstein的傻瓜目标-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
我在了解Transaction.m文件中的支出方法时遇到问题
id类型实例变量可以在包含它的类中调用ANY方法吗? 我知道respondsToSelector是一个NSObject方法,它告诉编译器是否已经实现了一个方法。但如何委托id-type的那个方法呢?编译器甚至不知道它到底是什么对象......
请帮忙!
P.S。如果有人对好的Objective-C书籍有任何建议,我会非常感激。我想进入iPhone开发,但我认为我需要先掌握Objective-C的基础知识。
谢谢!
答案 0 :(得分:2)
是的,您可以向delegate
变量发送任何消息,因为其类型为id
。
你写了这个:
[delegate spend:self];
编译器将其转换为对objc_msgSend
函数的调用,如下所示:
objc_msgSend(delegate, @selector(spend:), self);
在运行时,objc_msgSend
函数在delegate
的类(及其超类)的方法表中搜索与选择器spend:
关联的方法
顺便提一下,我们通常会像这样声明delegate
变量:
id<TransactionDelegate> delegate;
这通知编译器delegate
将是符合TransactionDelegate
协议的对象。当您尝试向delegate
发送消息时,此声明将帮助Xcode为您提供更好的自动完成功能。如果以这种方式声明delegate
setter方法或属性,编译器还将在编译时检查您是否将其设置为符合协议的对象。
答案 1 :(得分:1)
好问题。获取Obj-C和其他编译语言之间的主要区别之一。
您可以向任何您喜欢的Objective-C对象发送任何消息。消息send将尝试由称为运行时库的库解析,这在运行时发生。在编译时,如果您的对象类型不是通用ID,则某些IDE可能会将其标记为可能的用户错误。
在运行时,运行时库将查找匹配的方法,然后查看该类是否具有需要它的回退处理程序,并作为最后的手段抛出异常。用户代码可以很好地捕获此异常并将其视为正常情况。