在哪里以及如何__bridge
我需要关于iOS中__bridge
-ing的一些build议。
希望下面的SSCCE 1能更好地解释这个问题,但我需要知道如何将void*
转换为NSMutableArray*
; 应该使用__bridge
变体(参见代码注释)。
读了不同的桥梁,我推断,我将需要__bridge_transfer
但接着我收到addObject的addObject:
最终,我想在调用CGPath
之后在CGPoints
中创build一个CGPath
数组。
#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关键字的文档可以在这里find 。 具体来说,我想指出§3.2.4:
(__bridge T) op
将操作数转换为目标typesT.如果T是可保留的对象指针types,则op必须具有不可保留的指针types。 如果T是一个不可保留的指针types,那么op必须有一个可保留的对象指针types。 否则,演员阵容不健全。 没有所有权转让,并且ARC不插入保留操作。
(__bridge_retained T) op
将必须具有可保留对象指针types的操作数强制转换为目标types,该目标types必须是不可保留的指针types。 ARC会保留这个值,但是必须遵守本地值的通常优化,接收者负责平衡+1。
(__bridge_transfer T) op
将必须具有不可保留的指针types的操作数强制转换为目标types,该types必须是可保留的对象指针types。 ARC将在封闭的完整expression式的末尾释放该值,受当地值的通常优化。
你传入的指针( void*
)是一个不可保留的指针types,而你的NSMutableArray是一个可保留的指针types。 这直接排除了__bridge_retained
。 所以问题是, __bridge
或__bridge_transfer
?
__bridge_transfer
通常用于从返回已保留的CF对象的方法中获取Objective-C指针。 例如,CFStringCreateWithFormat将返回一个保留的CFString,但是如果你想要一个NSString,你需要在它们之间进行__bridge_transfer
。 这将使ARC在合适的时候释放CF保留的对象。 例如, NSString* str = (__bridge_transfer NSString*) CFStringCreateWithFormat(...);
你的代码没有这样做,你不需要干涉所有权。 你的主要方法是控制它的内存pipe理,只是简单的传递一个它所调用的方法的引用(虽然是间接的,但都在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}" )
我不太确定这是为什么,但我发现解决scheme是:
NSMutableArray *array = (__bridge NSMutableArray*) info; //AND CGPathApply(path, (__bridge void*)pathPoints, _processPathElement);
如果有人能解释为什么这个工作,并确认没有(/)有任何内存泄漏,我会很感激