11

私は ARC を使用していますが、使用中に混乱し__bridge_transferます。次のようなプロパティがありuserNameます。

@property (nonatomic, retain) NSString *userName;
...
@synthesize userName = _userName;
...

ケース1 :

NSString *name = (__bridge_transfer NSString *)ABRecordCopyCompositeName(person);
self.userName = name;

ケース2 :

self.userName = (__bridge_transfer NSString *)ABRecordCopyCompositeName(person);

personタイプABRecordRefです。

CASE 1では、ARC はローカル変数名を解放します (私の理解によると、間違っている場合は修正してください)。ただし、CASE 2 ではどうなりますか? __bridgeCASE 2で使用する必要がありますか、または CASE 2はまったく使用しないでください。またはを使用した CASE 2では、参照カウントのバランスを取る方法は?__bridge_transfer__bridge

CASE 2の with__bridge_transferでは、ARC はオブジェクト (引数として setter に渡されているオブジェクト) を解放します(void)setUserName:(NSString *)userNameか?

4

3 に答える 3

22

を呼び出すとABRecordCopyCompositeName()誰かが返されたオブジェクトをある時点で解放する必要があります。を使用__bridge_transferすると、ARC がオブジェクトを解放します。がない__bridge_transfer場合は、返されたオブジェクトを手動で解放する必要があります。これらは唯一の2つのオプションです。

__bridge_transferしたがって、両方の場合に使用する必要があります。

__bridgeの代わりに を使用してリークを誘発し、 __bridge_transferXcode と Instruments を使用してリークを見つけようとするのは良い演習です。コンパイラはリークを検出しますか? 静的分析 (プロジェクト -> 分析) でリークが検出されますか? 機器は漏れを拾いますか? __bridge_transferその場合、問題が解決するかどうかを確認する方法がわかります。

于 2013-01-16T07:09:43.000 に答える
4

ケース 1 とケース 2 は同等です。次のように考えてください。

ケース 1:

-(void)func {
  NSString *name = someObject;  // Retain, so +1 on the reference count
  self.userName = name;         // Retain, so +1 on the reference count
  // End of function, name is going out of scope,
  // so release name, so -1 on the reference count.
  // Total change to the reference count: +1 for self.userName.
}

ケース 2:

-(void)func {
  self.userName = someObject;   // Retain, so +1 on the reference count
  // End of function.
  // Total change to the reference count: +1 for self.userName.
}

したがって、それらは同じように機能します。安全に実行できる場合、コンパイラは保持と解放のペアをキャンセルできることに注意してください。このような単純なケースでは、確かにそれらを除外します。参照カウントに +1 と -1 のすべての変更を加えて考えると、わかりやすくなります。

__bridge と __bridge_transfer の違いについて少し答えるには、 を呼び出しましABRecordCopyCompositeNameた。これは、管理されていないオブジェクト (a CFStringRef) への参照を返します。関数名のCopyは、このオブジェクトが現在あなたによって所有されており、最終的に解放する必要があることを示しています。

に電話してこれを行うかCFRelease、ARC に依頼することができます。 __bridge所有権を取得できないことを ARC に通知します (つまり、オブジェクトを手動で解放したい、または所有していないことを示します)。 __bridge_transfer所有権を取得し、式全体の最後でオブジェクトを解放する必要があることを ARC に伝えます (つまり、ARC に解放を依頼していることになります)。

__bridge_transfer:

self.userName = (__bridge_transfer NSString *)ABRecordCopyCompositeName(person);  // +1 inside ABRecordCopyCompositeName, +1 for self.userName, -1 at the end, because of the __bridge_transfer.
// self.userName now is the only strong reference.  Good.

__bridge:

CFStringRef userName = ABRecordCopyCompositeName(person);  // +1 inside ABRecordCopyCompositeName.
self.userName = (__bridge NSString *)userName;             // +1 for self.userName, ARC does nothing because of the __bridge.
CFRelease(userName);                                       // -1.
// self.userName now is the only strong reference.  Good.

__bridgeメモリリーク:

self.userName = (__bridge NSString *)ABRecordCopyCompositeName(person);  // +1 inside ABRecordCopyCompositeName, +1 for self.userName, ARC does nothing because of the __bridge.
// self.userName now is one strong reference, but reference count is 2.
// Memory leak.
于 2015-02-13T08:27:29.887 に答える
1

これは紛らわしいため、andをそれぞれキャストするよりもCFBridgingRelease()andを使用することをお勧めします。次に、覚えておく必要がある唯一の「異常な」キャストは です。これは、所有権とは関係ありません。CFBridgingRetain()__bridge_transfer__bridge_retained__bridge

返されたオブジェクトABRecordCopyCompositeName()に対する責任をあなたに残すようなものを使用すると、その責任を解放するために使用でき、アナロジーが明らかであるため、覚えやすいと思います。CFRelease()CFBridgingRelease()

同様に、オブジェクト ポインターが既に Core Foundation 型である場合CFBridgingRetain()に使用するコンテキストでのみ使用します。CFRetain()

したがって、コードは次のようになります。

NSString *name = CFBridgingRelease(ABRecordCopyCompositeName(person));
self.userName = name;

または:

self.userName = CFBridgingRelease(ABRecordCopyCompositeName(person));

どちらの場合も、オブジェクトを解放する責任があることを意味する関数名のCFBridgingRelease()バランスが取れています。Copy後は全て他人の責任です。ARC がname変数を管理します。プロパティのセッターの実装者がuserNameそれを管理します。(この場合も ARC ですが、それは関係ありません。)

于 2015-09-11T02:25:58.957 に答える