Jam*_*ter 33 memory-management core-graphics objective-c cgpath ios
我需要__bridge在iOS 上提供一些建议.
希望在SSCCE 1下面会解释这个问题比我的话比较好,但我需要知道我可以转换void*成NSMutableArray*; __bridge应该使用哪种变体(参见代码中的注释).
阅读不同的桥梁,我推断出我需要,__bridge_transfer但后来我收到了一个EXC_BAD_ACCESSaddObject:
最终,我想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);
}
}
Run Code Online (Sandbox Code Playgroud)
1:SSCCE
WDU*_*DUK 60
有关使用bridge关键字的文档可以在这里找到.具体来说,我想指出§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的范围内).因此,你会使用__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);
}
}
Run Code Online (Sandbox Code Playgroud)
这将打印出来:
Points:(
"NSPoint: {0, 0}",
"NSPoint: {1, 0}",
"NSPoint: {1, 1}",
"NSPoint: {0, 1}"
)
Run Code Online (Sandbox Code Playgroud)