【问题标题】:How is type safety possible for an object pointer of id?id 的对象指针如何实现类型安全?
【发布时间】:2014-06-01 16:40:13
【问题描述】:

我有以下课程(从 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 是如何知道这一点,甚至在代码完成中建议该方法的?

【问题讨论】:

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


    【解决方案1】:

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

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

    for (id service in connectedServices) {
        if ([service isKindOfClass:[LeTemperatureAlarmService class]] && [service servicePeripheral] == parameter) {
            ...
        }
    }
    

    【讨论】:

    • 但是 XCode 怎么可能在 Code Completion 中建议 servicePeripheral 呢?这只是一个疯狂的猜测吗?
    • @Evils 是的。请注意,代码完成将允许您将任何方法发送到类型为id 的对象。顺便说一句,是Xcode 而不是XCode
    • 向 nil 发送方法永远不会返回 NULL。它将返回 nil。
    • @CrimsonChris nil, NULL, false 和 0 都一样。
    • 不要与 NSNull 混淆,这是不同的。抱歉,我听到 null,我认为是 NSNull。
    【解决方案2】:

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

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

    您对此保持警惕是完全正确的,因为它可能会导致您稍后崩溃。它是 not (正如你的问题标题所说的那样)“类型安全”。这是类型不安全!编译器会很乐意让你说(例如)[service count](因为service 被键入为id),但是稍后当应用程序运行时你会崩溃,因为这个对象没有响应count 消息.

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

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-09-04
    • 1970-01-01
    • 2013-03-27
    • 2023-02-09
    • 1970-01-01
    • 1970-01-01
    • 2014-03-18
    相关资源
    最近更新 更多