在哪里以及如何 __bridge

Posted

技术标签:

【中文标题】在哪里以及如何 __bridge【英文标题】:Where and how to __bridge 【发布时间】:2013-01-29 01:21:05 【问题描述】:

我需要一些关于 ios__bridge-ing 的建议。

希望下面的 SSCCE1 能比我用文字更好地解释这个问题,但我需要知道如何将 void* 转换为 @987654324 @;应该使用哪个__bridge 变体(参见代码中的注释)。

阅读了不同的桥梁,我推断我需要__bridge_transfer,但随后我在addObject: 上收到了一个 EXC_BAD_ACCESS

最终,在调用CGPathApply 之后,我希望在CGPath 中有一个CGPoints 数组。

#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

【问题讨论】:

我不明白。我只是按照 Xcode 的建议使用了__bridge。然后你的程序就编译好了。 或者你正在寻找这个,__bridge 在 Objective-C 和 Core Foundation 之间传输一个指针,而不转移所有权。 __bridge_retainedCFBridgingRetain 将 Objective-C 指针转换为 Core Foundation 指针,并将所有权转移给您。您负责调用 CFRelease 或相关函数来放弃对象的所有权。 __bridge_transferCFBridgingRelease 将非 Objective-C 指针移动到 Objective-C 并将所有权转移给 ARC。 ARC 负责放弃对象的所有权。 @BlackFlam3(第 1 条评论)这不仅仅是让代码编译的情况。我需要正确保留内存,以便我可以访问pathPointsNSLog @BlackFlam3(第 2 条评论)我在另一个网站上读到过,并推断我需要 __bridge_transfer,但随后我在 addObject: 上收到了 EXC_BAD_ACCESS 【参考方案1】:

有关使用 bridge 关键字can be found here 的文档。具体来说,我想指出§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。那么问题来了,__bridge 还是__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。您需要传递指针本身,而不是指向指针的指针。 但是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"
)

【讨论】:

谢谢。 =]我想你正在写这篇文章,因为我发现并发布了(相同的)结论。不过,您的回答提供了更多信息,并确认我偶然发现了正确的解决方案。 请注意,使用CFBridg* 变体通常更清晰(对我们中的一些人来说,无论如何)。【参考方案2】:

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

NSMutableArray *array = (__bridge NSMutableArray*) info;

//AND

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

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

【讨论】:

我在输入答案时错过了这个(所以没有通知我新的答案)。请参阅上面的理由。

以上是关于在哪里以及如何 __bridge的主要内容,如果未能解决你的问题,请参考以下文章

在 joomla 组件中,我应该在哪里存储数据库函数,以及如何调用它们?

如何在 Pytorch 中实现 dropout,以及在哪里应用它

逛吃米兰 | 米兰漫画看哪里??__SUPERGULP

我如何告诉 django-nose 我的测试在哪里?

CUDA C __device__ 函数中的 __forceinline__ 效果

陈松松:视频营销到底难在哪里,要如何解决?