4

ID __autoreleasing * から CFTypeRef * (void **) にキャストしようとしています。

私はもう試した:

id __autoreleasing *arg = [OCMArg setTo:mockData];

CFTypeRef expectedResult = (__bridge CFTypeRef) *arg;

[[[self.mockSecItemService expect] andReturnValue:OCMOCK_VALUE(mockCopyStatus)] copyItemMatching:queryCheck
                                                                                          result:&expectedResult];

しかし、自動解放プールが空になるとコードがクラッシュします。

ARC 環境で void** に変換するにはどうすればよいですか?

4

2 に答える 2

3

私はあなたが使用している API を知らないので、何が起こっているのか 100% 確信が持てません。グーグルで調べたところ、OCMock の一部のようです。私はそれをダウンロードし、(興味がないのでインストールせずに) ソースをすばやくブラウズしました。

そのコードには非常に怪しいものがあります。最初に呼び出すメソッドを実装する方法は次のとおりです。

@implementation OCMArg

....

+ (id *)setTo:(id)value
{
    return (id *)[[[OCMPassByRefSetter alloc] initWithValue:value] autorelease];
}

したがって、彼らは を返していますが、id*これは本当に単なるidです。

私にとって、それはナンセンス/エラーか、ObjC 内部を操作しようとする試みのいずれかです (たとえ文書化されていなくても、ObjC オブジェクトが格納する最初のものは、実際にはオブジェクト クラスへのポインターであり、したがってClassと互換性のある型でありid、したがって何らかの形でオブジェクトへのポインター、またはidオブジェクトを参照する へのポインターをキャストするのに有効)。なぜ彼らがそうするのかを理解するためにAPI全体を調査する時間も興味もありません。実際には正当な理由がある場合があります (たとえば、その結果を別の API に渡すだけで、その結果が本来あるべきことを認識しているが、ここではそれ以上のことを行っている場合など)。OCMock を勉強する代わりに、私が言える範囲で何が起こっているか (ObjC と ARC) を説明しようと思います。Class*id*

id __autoreleasing *arg = [OCMArg setTo:mockData];

このコード行では、ARC はまったく何もしません。

その方法は上で見ることができます。クラスOCMPassByRefSetterは、引数を保持した後に格納するだけの単純なクラスなので、mockData保持されます。はOCMPassByRefSetter自動解放され、次のドレインで消えます (解放されたメモリを解放しmockData 参照*argします)。

実際にはの をarg指していることに注意してください(は任意のオブジェクトの「最初の」 ivar であり、型であり、オブジェクトのクラスを指します。ただし、これは文書化されておらず、いつでも変更される可能性があります)。isaOCMPassByRefSetterisaClass

CFTypeRef expectedResult = (__bridge CFTypeRef) *arg;

*argidはと互換性のある型であるCFTypeRefため、キャストは有効です。あなたが使用し__bridgeているので、ARCはまったく何もしません。

arg「無料でブリッジされた」CF/Cocoa クラスを指している場合、これは完全に有効なコードですがexpectedResult、次のドレインで無効になることに注意する必要があります (そうではありませんretainedが、自動解放されたインスタンスとして有効です)。

[[[self.mockSecItemService expect] andReturnValue:OCMOCK_VALUE(mockCopyStatus)] copyItemMatching:queryCheck
                                                   result:&expectedResult];

この行が何をするのかわかりません。上記のコメントに投稿したプロトタイプを考えると、ARC は何もしませんresult:&expectedResult

あなたはそれがラッパーの周りだと言いますSecItemCopyMatchingが、私が理解しているように、それ以上のものです。SecItemCopyMatching引数を渡してすぐに呼び出していたresult:場合は、おそらく混乱しているでしょう。しかし、名前expectedResultとこれが OCMock であるという事実から、これはそれよりも少し複雑だと思います。

少し自分で調べる必要があります。でも覚えておいて:

  • 現在の関数が終了するとすぐに、渡した引数 ( &expectedResult) はローカル変数であるため無効になります。
  • ドレインが発生するとすぐに、 のexpectedResult無効になります。これは、そのアドレスがドレインによって割り当て解除されるメモリを指しているためです。
  • の値を使って何かをすることは、非常expectedResultうまくいかない可能性が高いですClass

OCMock API を意図したとおりに使用していないのではないかと思いますが、非常に間違っている可能性があります。しかし、この面では私はあなたを助けることはできません。

于 2012-08-13T23:59:01.233 に答える
0

変数を正しい形式にキャストする方法を考えるのではなく (OCMock は内部で複雑なことを行っています)、変換を処理する別のメソッドを追加しました。

- (OSStatus)findItemMatching:(NSDictionary *)query result:(id __autoreleasing *)outResult {
    NSAssert(outResult, @"outResult is required");

    CFTypeRef result = nil;
    OSStatus status = [self copyItemMatching:query result:&result];

    if (result) {
        *outResult = CFBridgingRelease(result);
    }

    return status;
}
于 2012-08-14T00:32:08.017 に答える