3

我关于stackoverflow的第一个问题,所以请温柔。我试过寻找答案,但我真的需要帮助。

问题在于从 Neal Goldstein 的 Objective-C for Dummies 中学习代表

他在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 类型实例变量可以调用包含它的类中的任何方法吗?我知道 respondsToSelector 是一个 NSObject 方法,它告诉编译器是否已经实现了一个方法。但是,哪个是 id 类型的委托如何调用该方法呢?编译器甚至还不知道它是什么对象......

请帮忙!

PS如果有人对好的Objective-C书籍有任何建议,我将不胜感激。我想进入 iPhone 开发,但我认为我需要先掌握 Objective-C 的基础知识。

谢谢!

4

2 回答 2

2

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

你写了这个:

[delegate spend:self];

编译器将其转换为对objc_msgSend函数的调用,如下所示:

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

在运行时,该objc_msgSend函数在delegate的类(及其超类)的方法表中搜索与选择器关联的方法spend:

顺便说一句,我们通常delegate这样声明变量:

id<TransactionDelegate> delegate;

这会通知编译器delegate将成为符合TransactionDelegate协议的对象。这个声明将帮助 Xcode 在您尝试向delegate. 如果您delegate以这种方式声明您的 setter 方法或属性,编译器还将在编译时检查您是否将其设置为符合协议的对象。

于 2013-03-11T18:14:51.837 回答
1

好问题。了解 Obj-C 与其他编译语言之间的主要区别之一。

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

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

于 2013-03-11T19:52:22.887 回答