2013-02-13 8 views
27

私は__bridge-iOSに関するアドバイスが必要です。__bridgeの場所と方法

うまくいけばSSCCE以下は、私は言葉にすることができますより良い問題を説明しますが、私はNSMutableArray*void*を変換する方法を知っておく必要があります。どのような変更を使用する必要があります(コードのコメントを参照してください)。

異なる橋梁について読んで、私は、私がCGPathCGPathApplyCGPointsの配列を持っているしたいと呼ばれてきた私は__bridge_transferが必要になりますが、その後、私は最終的にaddObject:

にEXC_BAD_ACCESSを受けることが推定しました。

#import <Foundation/Foundation.h> 

void _processPathElement(void* info, const CGPathElement* element) 
{ 
    NSMutableArray *array = (/* WHAT BRIDGE HERE */ NSMutableArray*) info; 
    switch (element->type) 
    { 
     case kCGPathElementMoveToPoint: 
     case kCGPathElementAddLineToPoint: 
     { 
      CGPoint point = element->points[0]; 
      [array addObject:[NSValue valueWithCGPoint:point]]; 
      break; 
     } 
     default: 
      break; 
    } 
} 

int main(int argc, char *argv[]) 
{ 
    @autoreleasepool 
    { 
     //Create path 
     CGMutablePathRef path = CGPathCreateMutable(); 
     CGPathMoveToPoint( path, NULL, 0, 0); 
     CGPathAddLineToPoint(path, NULL, 1, 0); 
     CGPathAddLineToPoint(path, NULL, 1, 1); 
     CGPathAddLineToPoint(path, NULL, 0, 1); 
     CGPathCloseSubpath(path); 

     NSMutableArray *pathPoints = [NSMutableArray array]; 
     CGPathApply(path, &pathPoints, _processPathElement); 

     NSLog(@"Points:%@", pathPoints); 
    } 
} 

1:SSCCE

+0

私は理解していません。 Xcodeが提案したように '__bridge'を使用しました。そしてあなたのプログラムはコンパイルされます。 – esh

+3

これを探しているのですが、 '__bridge'はObjective-CとCore Foundationの間のポインタを所有権の移譲なしに転送します。 '__bridge_retained'または' CFBridgingRetain'は、Objective-CポインタをCore Foundationポインタにキャストし、あなたに所有権を移します。 CFReleaseまたは関連する機能を呼び出して、オブジェクトの所有権を放棄する責任があります。 '__bridge_transfer'または' CFBridgingRelease'は、非Objective-CポインタをObjective-Cに移動し、所有権をARCに転送します。 ARCはオブジェクトの所有権を放棄します。 – esh

+0

@ BlackFlam3(第1のコメント)コンパイルするコードを取得するだけではありません。 'NSLog'の' pathLogs'にアクセスできるようにメモリを確保する必要があります。 –

答えて

47

Tブリッジキーワードcan be found hereの使用に関するドキュメント具体的には、私は§3.2.4を指摘したい:

(__bridge T) opはTが保持できるオブジェクトのポインタ型である場合には、opが非保持可能なポインタ型を持っている必要があります先の型Tにオペランドをキャストします。 Tが保持不能なポインタ型である場合、opは保持可能なオブジェクトポインタ型を持たなければならない。さもなければ、キャストは不正な形になります。所有権の移転はなく、ARCは保持操作を挿入しません。

(__bridge_retained T) opは、保持可能なオブジェクトポインタ型を持たなければならないオペランドを、保持不可能なポインタ型でなければならないデスティネーション型にキャストします。 ARCはローカル値の通常の最適化を前提として値を保持し、受信者はその+1のバランスを取る責任があります。

(__bridge_transfer T) opは、保持不可能なポインタ型を持たなければならないオペランドを、保持可能なオブジェクトポインタ型でなければならないデスティネーション型にキャストします。 ARCは、ローカル値の通常の最適化を条件に、囲み式の最後に値を解放します。

あなたが渡しているポインタ(void*)は、保持不可能なポインタ型ですが、NSMutableArrayは保持可能なポインタ型です。これはすぐに__bridge_retainedを除外します。ですから質問は、__bridgeまたは__bridge_transferに?

__bridge_transferは、保持されているCFオブジェクトを返すメソッドからObjective-Cポインタを取得する場合に使用されます。たとえば、CFStringCreateWithFormatは保持されているCFStringを返しますが、そこからNSStringが必要な場合は、その間に__bridge_transferが必要です。これにより、適切なときにCFが保持するオブジェクトがARCによって解放されます。たとえば、NSString* str = (__bridge_transfer NSString*) CFStringCreateWithFormat(...);

あなたのコードはそれをしていないので、所有権に干渉する必要はありません。あなたの主な方法は、メモリ管理を制御することであり、単に呼び出すメソッドへの参照を渡すだけです(間接的ですが、すべてがメインのスコープ内にあります)。したがって、__bridgeを使用します。

__bridgeを使用すると、コードにメモリアクセスエラーが発生します。

ああ、これはあなたが投稿したコードの問題であり、ブリッジングの議論全体とは関係ありません。処理関数_processPathElementのために、void*をCGApplyPathに渡す必要があります。あなたが渡しているのはNSMutableArray**です。

NSMutableArray*にリキャストすると、実際にはNSMutableArray**がキャストされます。これは悪名高いEXC_BAD_ACCESSを引き起こします。ポインターへのポインターではなく、ポインター自体を渡す必要があります。 CGPathApply(path, pathPoints, _processPathElement)は機能しません。NSMutableArray*void*として渡すことはできません。あなたが必要とするもの(皮肉なことに)は、橋です。前と同じ理由から、必要なのは__bridgeです。代わりに、正しいブリッジと、コードの下を参照してください、そして期待通りに動作:

#import <UIKit/UIKit.h> 
#import <Foundation/Foundation.h> 

void _processPathElement(void* info, const CGPathElement* element) 
{ 
    NSMutableArray *array = (__bridge NSMutableArray*) info; 
    switch (element->type) 
    { 
     case kCGPathElementMoveToPoint: 
     case kCGPathElementAddLineToPoint: 
     { 
      CGPoint point = element->points[0]; 
      [array addObject:[NSValue valueWithCGPoint:point]]; 
      break; 
     } 
     default: 
      break; 
    } 
} 

int main(int argc, char *argv[]) 
{ 
    @autoreleasepool 
    { 
     //Create path 
     CGMutablePathRef path = CGPathCreateMutable(); 
     CGPathMoveToPoint( path, NULL, 0, 0); 
     CGPathAddLineToPoint(path, NULL, 1, 0); 
     CGPathAddLineToPoint(path, NULL, 1, 1); 
     CGPathAddLineToPoint(path, NULL, 0, 1); 
     CGPathCloseSubpath(path); 

     NSMutableArray *pathPoints = [[NSMutableArray alloc] init]; 
     CGPathApply(path, (__bridge void*)pathPoints, _processPathElement); 

     NSLog(@"Points:%@", pathPoints); 
    } 
} 

これは、プリントアウトします:

Points:(
    "NSPoint: {0, 0}", 
    "NSPoint: {1, 0}", 
    "NSPoint: {1, 1}", 
    "NSPoint: {0, 1}" 
) 
+0

ありがとうございます。 =]私が見つけて投稿した(同じ)結論として、あなたがこれを書いていると想像します。あなたの答えはさらに多くの情報を提供し、私が正しいソリューションを見つけたことを確認します。 –

+0

'CFBridg *'バリアントの使用は、(私たちの中には、とにかく)もっと明確になることに注意してください。 – bbum

1

私は、なぜこの作品実際にはわからないんだけど、私は解決策があることが判明しました:誰もが理由を説明することができる場合

NSMutableArray *array = (__bridge NSMutableArray*) info; 

//AND 

CGPathApply(path, (__bridge void*)pathPoints, _processPathElement); 

これは動作し、メモリリークがないことを確認します。

+1

私は答えを入力するときにこれを逃しました(私は新しい答えを知らなかった)。これの根拠については上記を参照してください。 – WDUK

関連する問題