4

ブリッジング ヘッダーを使用して Swift で使用できる目的の C ライブラリがあります。

私のパブリック メソッドの 1 つは、返すと注釈が付けられて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 標準を何十回も読みましたが、その中にはそのような間違いがたくさんあります。その結果、通常、未定義の動作が発生します。結果が明確なクラッシュというわけではありません。私はそのような「約束」を読んだことがありません。そして、それは意味がありません。

したがって、簡単に言えば、動作は未定義です。未定義の動作には、何もクラッシュしない可能性が含まれます。

どうすればそれが起こりますか?

非 null に注釈を付けると、コンパイラーは、状況によってはコードを改善する機会を与えられますが、そうでない場合もありますコンパイラーが最適化によって得られる利点があるかもしれません。しかしもちろん、コンパイラがそうできない状況もあります。

Objective-C オブジェクトを取得するため、そのオブジェクトへのすべてのメッセージを実行時にディスパッチする必要があります。Swift でそのオブジェクトを使用しても、コンパイル時にそれを行う方法はありません (少なくともメソッドを置き換えることができ、メソッドをサブクラスで上書きすることができます)。動的ディスパッチは、Sift コンテキストに配置した場合でも、Objective-C が機能する方法です。

したがって、Swift 呼び出しは Objective-C メッセージになります。Objective-C メッセージは Objective-C ランタイムによって配信され、これはメッセージを nil まで処理できます。それで問題ありません。

オブジェクトに別のことが起こると、クラッシュする可能性があります。私はe。生成されたコードがポインターにアクセスしようとするとisa、null ポインター例外が発生する可能性があります。

多分。そうでないかもしれない。これは未定義です。

于 2016-10-17T19:54:30.557 に答える