40

__bridgeiOSでの-ingに関するアドバイスが必要です。

以下のSSCCE1が、私が言葉で表現できるよりも問題をうまく説明してくれることを願っていますが、 avoid*NSMutableArray*;に変換する方法を知る必要があります。どの__bridgeバリエーションを使用する必要がありますか(コードのコメントを参照)。

さまざまなブリッジについて読んで、私は必要__bridge_transferだと推測しましたが、その後、EXC_BAD_ACCESSを受け取りますaddObject:

CGPoints最終的には、CGPath後の配列を呼び出してもらいたいと思いCGPathApplyます。

#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

4

2 に答える 2

68

bridgeキーワードの使用に関するドキュメントは、ここにあります。具体的には、§3.2.4を指摘したいと思います。

(__bridge T) opオペランドをデスティネーション型Tにキャストします。Tが保持可能なオブジェクトポインタ型である場合、opは保持不可能なポインタ型である必要があります。Tが保持不可能なポインター型である場合、opは保持可能なオブジェクトポインター型を持っている必要があります。そうしないと、キャストの形式が正しくありません。所有権の譲渡はなく、ARCは保持操作を挿入しません。

(__bridge_retained T) op保持可能なオブジェクトポインタ型である必要があるオペランドを、保持不可能なポインタ型である必要がある宛先型にキャストします。ARCは、ローカル値の通常の最適化に従って値を保持し、受信者はその+1のバランスを取る責任があります。

(__bridge_transfer T) op保持不可能なポインター型でなければならないオペランドを、保持可能なオブジェクトポインター型でなければならない宛先型にキャストします。ARCは、ローカル値の通常の最適化に従って、囲んでいる完全式の最後に値を解放します。

渡されるポインター(void*)は保持不可能なポインター型ですが、NSMutableArrayは保持可能なポインター型です。これは__bridge_retainedすぐに除外されます。だから問題は、to__bridgeまたはto __bridge_transfer

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

あなたのコードはそれをしていません、あなたは所有権に干渉する必要はありません。mainメソッドはそのメモリ管理を制御しており、呼び出すメソッドへの参照を渡すだけです(間接的ではありますが、すべてmainの範囲内です)。そのため、を使用します__bridge

しかし、待ってください。__bridgeを使用すると、コードでメモリアクセスエラーが発生します!?

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

にリキャストすると、NSMutableArray*実際にはをキャストしていることになりますNSMutableArray**。これにより、悪名高いEXC_BAD_ACCESSが発生します。ポインタへのポインタではなく、ポインタ自体を渡す必要があります。ただし、は機能しません。aをとして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}"
)
于 2013-02-13T14:28:46.413 に答える