4

我有一个目标 c 库,可以使用桥接头在 Swift 中使用。

我的一个公共方法被注释为返回nonnull,但实际上在某些情况下它可以返回 nil。

我原以为调用此方法的 Swift 代码会崩溃,因为“解包 nil 可选值”,但实际上并没有。

目标-C:

- (nonnull UserService *)users
{
    if (!_users && [self checkStarted]) {
        _users = [[UserService alloc] init];
    }
    return _users;
}

-(BOOL) checkStarted
{
    return NO;
}

斯威夫特标题:

生成标头如下所示:

func users() -> UserService

迅捷用法:

let userService = sdk.users()

当我po返回值时,我得到了这个结果

po userService
<uninitialized>

怎么会?

4

1 回答 1

0

也许有一个误解:在许多编程语言中,您可能会犯很多错误,例如注释值约束然后不满足它。我已经阅读了数十次 C 标准,其中包含许多此类错误。结果通常是你得到一个未定义的行为。并不是说结果是确定的崩溃。我从未读过这样的“承诺”。这没有任何意义。

所以,简单地说:行为是undefined。未定义的行为包括没有任何崩溃的可能性。

怎么会这样?

注释非 null 使编译器有机会在某些情况下使代码更好,而在其他情况下则不然。编译器可以通过优化获得优势。但当然也有编译器不能这样做的情况。

由于您获得了一个 Objective-C 对象,因此必须在运行时分派到该对象的每条消息。即使您在 Swift 中使用该对象,在编译时也无法做到这一点(至少可以替换方法,可以在子类中覆盖方法等等)。动态调度是 Objective-C 的工作方式,即使你把它放在 Sift 上下文中。

所以 Swift 调用变成了一个 Objective-C 消息。Objective-C 消息由 Objective-C 运行时传递,它可以将消息处理为零。所以没有问题。

如果对象发生其他事情,您可能会崩溃。IE。如果生成的代码尝试访问isa指针,您可能会收到空指针异常。

也许。也许不吧。这是未定义的。

于 2016-10-17T19:54:30.557 回答