__bridge的位置和方式 [英] Where and how to __bridge

查看:119
本文介绍了__bridge的位置和方式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要对iOS中的 __ bridge -ing提出一些建议。

I need some advice on __bridge-ing in iOS.

希望SSCCE 1 会比我说的更好地解释问题,但我需要知道如何将 void * 转换为的NSMutableArray * ;应该使用 __ bridge 变体(参见代码中的注释)。

Hopefully the SSCCE1 below will explain the problem better than I can in words, but I need to know how I can convert a void* to an NSMutableArray*; which __bridge variation should be used (See comment in code).

阅读不同的桥梁,我推断出我需要 __ bridge_transfer 但是我在 addObject上收到一个EXC_BAD_ACCESS:

Reading about the different bridges, I deduced that I would need __bridge_transfer but then I receive an EXC_BAD_ACCESS on addObject:

最后,我想在<$ c后的 CGPath 中有一个 CGPoints 的数组已调用$ c> CGPathApply 。

Ultimately, I'd like to have an array of the CGPoints in the CGPath after CGPathApply has been called.

#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

推荐答案

可以在此处找到有关使用bridge关键字的文档。具体来说,我想指出§3.2.4:

The documentation on the use of the bridge keyword can be found here. Specifically, I want to point out §3.2.4:


(__ bridge T)op 将操作数强制转换为目标类型T.如果T是可保留的对象指针类型,则op必须具有不可保留的指针类型。如果T是不可保留的指针类型,则op必须具有可保留的对象指针类型。否则演员阵容不合理。没有所有权转让,ARC没有保留任何保留操作。

(__bridge T) op casts the operand to the destination type T. If T is a retainable object pointer type, then op must have a non-retainable pointer type. If T is a non-retainable pointer type, then op must have a retainable object pointer type. Otherwise the cast is ill-formed. There is no transfer of ownership, and ARC inserts no retain operations.

(__ bridge_retained T)op 强制转换操作数必须具有可保留对象指针类型的目标类型,它必须是不可保留的指针类型。 ARC保留该值,取决于对本地值的通常优化,并且收件人负责平衡+1。

(__bridge_retained T) op casts the operand, which must have retainable object pointer type, to the destination type, which must be a non-retainable pointer type. ARC retains the value, subject to the usual optimizations on local values, and the recipient is responsible for balancing that +1.

(__ bridge_transfer T) op 将操作数(必须具有不可保留的指针类型)强制转换为目标类型,该目标类型必须是可保留的对象指针类型。 ARC将在封闭的完整表达式的末尾释放值,这取决于对本地值的通常优化。

(__bridge_transfer T) op casts the operand, which must have non-retainable pointer type, to the destination type, which must be a retainable object pointer type. ARC will release the value at the end of the enclosing full-expression, subject to the usual optimizations on local values.

指针你传入( void * )是一种不可保留的指针类型,而NSMutableArray是一种可保留的指针类型。这将立即排除 __ bridge_retained 。所以问题是, __ bridge __ bridge_transfer

The pointer you're being passed in (void*) is a non retainable pointer type, whereas your NSMutableArray is a retainable pointer type. This rules out __bridge_retained straight away. So the question is, to __bridge or to __bridge_transfer?

__ bridge_transfer 通常在需要返回已保留的CF对象的方法的Objective-C指针时使用。例如,CFStringCreateWithFormat将返回一个保留的CFString,但是如果你想要一个NSString,你需要在它们之间 __ bridge_transfer 。这将使ARC在适当时释放CF保留的对象。例如, NSString * str =(__ bridge_transfer NSString *)CFStringCreateWithFormat(...);

__bridge_transfer is typically used when you want the Objective-C pointer from a method that returns a CF Object that has been retained. For example, CFStringCreateWithFormat will return a retained CFString, but if you want an NSString from it, you need to __bridge_transfer between them. This will make ARC release the object that CF retained when appropriate. For example, NSString* str = (__bridge_transfer NSString*) CFStringCreateWithFormat(...);

您的代码不是要做到这一点,你不需要干涉所有权。您的主要方法是控制其内存管理,并且只是将引用传递给它调用的方法(尽管是间接的,但它都在main的范围内)。因此,您将使用 __ bridge

Your code isn't doing that, you don't need to meddle with the ownership. Your main method is in control of its memory management, and is simply passing a reference to a method it calls (albeit indirectly, but it's all within the scope of main). As such, you would use __bridge.

但等等,当我使用__bridge时,我的代码获取内存访问错误!

啊,这是您发布的代码的问题,与整个桥接讨论无关。您需要将 void * 传递给CGApplyPath,以处理函数 _processPathElement 。你传递的是 NSMutableArray **

Ah, this is an issue with the code you posted, and isn't in relation to the whole bridging discussion. You need to pass a void* to CGApplyPath, for your processing function _processPathElement. What you're passing is NSMutableArray**.

当你重铸 NSMutableArray时* ,你实际上正在施放 NSMutableArray ** 。这将导致臭名昭着的EXC_BAD_ACCESS。您需要传递指针本身,而不是指针指针。 CGPathApply(path,pathPoints,_processPathElement)将无效,您无法传递 NSMutableArray * 作为 void * 。你需要什么(具有讽刺意味),是一座桥梁。出于与以前相同的原因,您只需要 __ bridge 。请参阅下面的代码,使用正确的桥接器,并按预期工作:

When you recast to the NSMutableArray*, you're actually casting a NSMutableArray**. This will cause the infamous EXC_BAD_ACCESS. You need to pass the pointer itself, not a pointer to a pointer. But, CGPathApply(path, pathPoints, _processPathElement) will not work, you cannot pass off a NSMutableArray* as a void*. What you need (ironically), is a bridge. For the same reasons as before, all you need is __bridge. See below the code, with the correct bridges in place, and working as expected:

#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}"
)

这篇关于__bridge的位置和方式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆