Ответ 1
Документацию по использованию ключевого слова 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
обычно используется, когда вам нужен указатель Objective-C из метода, который возвращает объект CF, который был сохранен. Например, CFStringCreateWithFormat вернет сохраненную CFString, но если вы хотите получить NSString, вам нужно __bridge_transfer
между ними. Это заставит ARC освободить объект, который CF сохранил, когда это необходимо. Например, NSString* str = (__bridge_transfer NSString*) CFStringCreateWithFormat(...);
Ваш код не делает этого, вам не нужно вмешиваться в собственность. Ваш основной метод контролирует управление памятью и просто передает ссылку на метод, который он вызывает (хотя и косвенно, но все это входит в объем основного). Таким образом, вы использовали бы __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}"
)