我需要一些关于 iOS 中
__bridge
-ing 的建议。
希望下面的示例能够比我用语言更好地解释问题,但我需要知道如何将
void*
转换为 NSMutableArray*
(即应该使用哪种 __bridge
变体)。
阅读有关不同桥梁的信息,我推断出我需要
__bridge_transfer
但随后我在 addObject:
上收到 EXC_BAD_ACCESS
最终,我希望在调用
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);
}
}
有关使用bridge关键字的文档可以在这里找到。具体来说,我想指出§3.2.4:
将操作数转换为目标类型 T。如果 T 是可保留对象指针类型,则 op 必须具有不可保留指针类型。如果 T 是不可保留的指针类型,则 op 必须具有可保留的对象指针类型。否则演员阵容就不健全。不存在所有权转移,ARC 不插入保留操作。(__bridge T) op
将操作数(必须具有可保留对象指针类型)转换为目标类型(必须是不可保留指针类型)。 ARC 保留该值,但会根据本地值进行通常的优化,而接收者负责平衡该 +1。(__bridge_retained T) op
将操作数(必须具有不可保留的指针类型)转换为目标类型(必须是可保留的对象指针类型)。 ARC 将在封闭的完整表达式末尾释放值,并根据本地值进行通常的优化。(__bridge_transfer T) op
您传入的指针(
void*
)是不可保留的指针类型,而您的 NSMutableArray 是可保留的指针类型。这立即排除了 __bridge_retained
。所以问题是,去__bridge
还是去__bridge_transfer
?
当您希望从返回已保留的 CF 对象的方法中获取 Objective-C 指针时,通常会使用 __bridge_transfer
。例如,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}"
)
我实际上不确定为什么会这样,但我发现解决方案是:
NSMutableArray *array = (__bridge NSMutableArray*) info;
//AND
CGPathApply(path, (__bridge void*)pathPoints, _processPathElement);
如果有人可以解释为什么它有效并确认没有(/是)任何内存泄漏,我将不胜感激