ios 在哪里以及如何 __bridge

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14854521/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 22:16:31  来源:igfitidea点击:

Where and how to __bridge

iosobjective-cmemory-managementcore-graphicscgpath

提问by James Webster

I need some advice on __bridge-ing in iOS.

我需要一些关于__bridge-ing 在 iOS 中的建议。

Hopefully the SSCCE1below 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 __bridgevariation should be used (See comment in code).

希望下面的 SSCCE 1能比我用文字更好地解释这个问题,但我需要知道如何将 a 转换void*为 an NSMutableArray*__bridge应该使用哪种变体(请参阅代码中的注释)。

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

阅读不同的桥梁,我推断我需要,__bridge_transfer但后来我收到了一个 EXC_BAD_ACCESSaddObject:

Ultimately, I'd like to have an array of the CGPointsin the CGPathafter CGPathApplyhas been called.

最终,我想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

1:SSCCE

回答by WDUK

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

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

(__bridge T) opcasts 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) opcasts 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) opcasts 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.

(__bridge T) op将操作数强制转换为目标类型 T。如果 T 是可保留的对象指针类型,则 op 必须具有不可保留的指针类型。如果 T 是不可保留的指针类型,则 op 必须具有可保留的对象指针类型。否则演员阵容是不合格的。没有所有权转移,ARC 插入没有保留操作。

(__bridge_retained T) op将必须具有可保留对象指针类型的操作数强制转换为目标类型,该类型必须是不可保留指针类型。ARC 保留该值,受制于对本地值的通常优化,并且接收者负责平衡 +1。

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

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_retainedstraight away. So the question is, to __bridgeor to __bridge_transfer?

您传入 ( void*) 的指针是不可保留的指针类型,而您的 NSMutableArray 是可保留的指针类型。这立即排除__bridge_retained了。所以问题是,去__bridge还是去__bridge_transfer

__bridge_transferis 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_transferbetween them. This will make ARC release the object that CF retained when appropriate. For example, NSString* str = (__bridge_transfer NSString*) CFStringCreateWithFormat(...);

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

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.

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

But wait, when I use __bridge, my code gets memory access errors!?

但是等等,当我使用 __bridge 时,我的代码会出现内存访问错误!?

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**.

啊,这是您发布的代码的问题,与整个桥接讨论无关。您需要将 a 传递void*给 CGApplyPath,用于您的处理功能_processPathElement。你正在传递的是NSMutableArray**.

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:

当你重铸到 时NSMutableArray*,你实际上是在投射一个NSMutableArray**. 这将导致臭名昭著的 EXC_BAD_ACCESS。您需要传递指针本身,而不是指向指针的指针。但是CGPathApply(path, pathPoints, _processPathElement)不起作用,您不能将 aNSMutableArray*作为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);
    }
}

This will print out:

这将打印出:

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

回答by James Webster

I'm not actually sure why this works, but I've found the solution to be:

我实际上不确定为什么会这样,但我发现解决方案是:

NSMutableArray *array = (__bridge NSMutableArray*) info;

//AND

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

If anyone can explain why this works and confirm that there aren't (/are) any memory leaks I'd be grateful

如果有人可以解释为什么这样做并确认没有(/是)任何内存泄漏,我将不胜感激