NSInvocation возвращает значение, но приводит к сбою приложения с EXC_BAD_ACCESS
У меня есть массив, который я повторяю и ищу конкретный флаг. Если значение флага равно nil, я вызываю метод, который генерирует объект вызова и возвращает результат вызова.
Моя структура кода выглядит следующим образом
for(NSString *key in [taxiPlanes allKeys])
{
Plane *currentPlane = [taxiPlanes objectForKey:key];
if(currentPlane.currentAction == nil)
{
NSString *selector = [[currentPlane planeTakeoffSequence] firstObject];
currentPlane.currentAction = selector;
// Calling for NSInvocation in [self ...]
NSArray *action = [NSArray arrayWithArray:[self operationFromTakeoffAction:currentPlane.currentAction AtPoint:currentPlane.position]];
NSLog(@"%@",action);
}
}
Метод, который генерирует NSInvocation
-(NSArray *) operationFromTakeoffAction:(NSString *) action AtPoint:(CGPoint) flightPoint
{
NSMethodSignature *methodSignature = [FlightOperations instanceMethodSignatureForSelector:NSSelectorFromString(action)];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature];
[invocation setTarget:fOps];
[invocation setSelector:NSSelectorFromString(action)];
[invocation setArgument:&flightPoint atIndex:2];
NSArray *resultSet = [NSArray alloc]init];
[invocation invoke];
[invocation getReturnValue:&resultSet];
return resultSet;
}
В цикле for, без вызова метода для NSInvocation ([self....]), цикл просто выполняется отлично и не сбой. Но когда я представляю метод для вызова NSInvocation, я могу видеть, что NSLog in для циклов печатает ожидаемый результат NSArray, но он выходит из строя с сообщением об ошибке EXC_BAD_ACCESS.
Я не могу понять, почему это не удается, хотя NSInvocation возвращает правильный результат. Без NSInvocation для цикла не сбой.
Любые предложения были бы полезными.
Спасибо
Ответы
Ответ 1
Я предполагаю, что вы используете ARC?
Проблема связана с линией [invocation getReturnValue:&resultSet];
. getReturnValue:
просто копирует байты возвращаемого значения в указанный буфер памяти независимо от типа. Он не знает и не заботится об управлении памятью, если тип возвращаемого значения является типом сохраняемого типа объекта. Поскольку resultSet
является переменной __strong
типа указателя объекта, ARC предполагает, что любое значение, которое было помещено в переменную, было сохранено и, таким образом, будет выпущено, когда оно выходит за рамки. В этом случае это не так, поэтому он падает. (Кроме того, массив, который вы указали на resultSet
, изначально указывает на утечку, поскольку getReturnValue:
перезаписывает это значение, не отпуская его. Почему вы даже сделали эту переменную точкой для объекта, в первую очередь, вне меня.)
Решение состоит в том, что вы должны указывать указатель на не сохраняемый тип на getReturnValue:
. Или:
NSArray * __unsafe_unretained tempResultSet;
[invocation getReturnValue:&tempResultSet];
NSArray *resultSet = tempResultSet;
или
void *tempResultSet;
[invocation getReturnValue:&tempResultSet];
NSArray *resultSet = (__bridge NSArray *)tempResultSet;
Ответ 2
Да, это только что произошло в ARC.
Я предполагаю, что это ошибка системы.
Например:
【IPhone4s + iOS8.4】, 【iphone 4 + iOS7.1】 (авария),
【IPhone6 + iOS9.3】, 【iphone 5 + iOS8.4.1】 (проход),
моя тестовая демонстрационная ссылка для скачивания https://github.com/leopardpan/IssuesDemo
Исходный код
NSArray *resultSet = [NSArray alloc]init];
[invocation invoke];
[invocation getReturnValue:&resultSet];
Чтобы решить следующие
случай 1:
void *temp = NULL;
[invocation invoke];
[invocation getReturnValue:&temp];
NSArray *resultSet = (__bridge NSArray*)temp;
случай 2:
__weak NSArray *resultSet = [NSArray alloc]init];
[invocation invoke];
[invocation getReturnValue:&resultSet];
случай 3:
__autoreleasing NSArray *resultSet = [NSArray alloc]init];
[invocation invoke];
[invocation getReturnValue:&resultSet];
случай 4:
__unsafe_unretained NSArray *resultSet = [NSArray alloc]init];
[invocation invoke];
[invocation getReturnValue:&resultSet];
Рекомендуется использовать case1, принцип должен быть @newacct указанным
Добро пожаловать, чтобы обсудить