如何对id的对象指针进行类型安全?

时间:2014-06-01 16:40:13

标签: objective-c types type-safety message-passing

我有以下课程(从Apple示例中挑选出来):

@interface LeTemperatureAlarmService : NSObject <CBPeripheralDelegate>
@property (readonly) CBPeripheral *servicePeripheral;
@end    

在另一个类的方法中,我使用以下代码:

NSMutableArray *connectedServices = [[NSMutableArray alloc] init];
... // Adding some myService objects to connectedServices

for (id service in connectedServices) {
    if ([service servicePeripheral] == parameter) {
        ...
    }
}

现在让我发疯的事情就是我可以将servicePeripheral发送给service的部分。

据我了解id如何工作,它基本上是一个指针,可以字面指向任何对象。我的NSMutableArray是一个无类型的数组,可以容纳任何类型的对象,甚至是混合的,所以我不必小心我放入的内容。

那么即使我从未指定过服务类型,我怎么能使用[service servicePeripheral]呢? Xcode如何知道这一点,甚至在代码完成中建议该方法?

2 个答案:

答案 0 :(得分:2)

Objective-C在方法调用方面的工作方式与C ++不同。编译器不必知道,因为它不是在编译时完成的,所以在运行时调用方法。具体而言,方法被发送到对象,而不是调用它们。您将servicePeripheral方法发送到对象,运行时负责调用正确的函数。这也使您可以将方法发送到nil而不会崩溃(它将返回false/0/NULL

Objective-C中的类型主要用于编译时安全性,您可以通过自己的方法将其丢失。编译器无法警告您类型不匹配,例如,您的数组很可能包含NSString实例或任何内容,并且编译器无法帮助您,因为您告诉它您期望{ {1}}(也就是任何东西,真的)和id是一种完全有效且已知的方法。您可以通过使用servicePeripheral在运行时检查对象的类来添加类型安全性,例如:

isKindOfClass:

答案 1 :(得分:2)

  

那么即使我从未指定过服务类型,我怎么能使用[service servicePeripheral]呢?

正是因为您将service声明为id。这告诉编译器关闭所有静态类型检查,并允许您将任何消息发送到service。这就是id :它是通用收件人(任何邮件都可以发送给它,任何对象值都可以分配给它)和通用捐赠者(可以分配给它任何对象变量)。

你完全正确地警惕这一点,因为它会导致你以后崩溃。这是(因为你的问题标题有它)&#34;输入安全&#34;。这种类型不安全!编译器很乐意让你说(例如)[service count](因为service被输入为id),但是当应用程序运行时你会崩溃,因为这个对象没有响应到count消息。

所以不要这样做!使用显式类型,以便编译器可以提前帮助您。