Как создать объект NSInvocation, используя метод, который принимает указатель на объект в качестве аргумента - PullRequest
4 голосов
/ 03 апреля 2012

Я хотел бы создать объект NSInvocation, используя метод, который принимает указатель на объект NSError в качестве аргумента.Примером этого может быть метод -

- (BOOL)writeToFile:(NSString *)path options:(NSDataWritingOptions)mask error:(NSError **)errorPtr

Я понимаю, что я бы настроил свой вызов так:

NSData *myData = [[NSData alloc] init];

SEL writeToFileSelector = @selector(writeToFile:options:error:);
NSMethodSignature *signature = [NSData instanceMethodSignatureForSelector:writeToFileSelector];

NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
[invocation setTarget:myData];
[invocation setSelector:writeToFileSelector];

NSString *string = [NSString stringWithFormat:@"long cat"];
NSDataWritingOptions *dataOptions;
*dataOptions = NSDataWritingFileProtectionComplete;

[invocation setArgument:&string atIndex:2];
[invocation setArgument:&dataOptions atIndex:3];

Для writeToFile: Опции: Ошибка: ожидается последний аргументполучить указатель вместо объекта.В результате выполнение следующего не работает -

NSError *err = nil;
[invocation setArgument:&err atIndex:4];

Кажется логичным, что решением может быть создание указателя на указатель, но это вызывает предупреждение компилятора.Я не уверен, как выполнить это правильно и не создать проблему управления памятью.

Ответы [ 3 ]

3 голосов
/ 04 апреля 2012

Вы создаете аргумент точно так же, как и любой другой аргумент, передаваемый методу.

Как вы указали, сигнатура метода требует NSError ** для своего последнего аргумента (индекс 4).Итак, вам нужно будет объявить один, но есть небольшая хитрость.

NSError **errorPointer

Дает вам переменную, которая указывает на переменную NSError.Но, поскольку вы не указали, чтобы он указывал на какую-либо переменную, он указывает на ноль.Поэтому, когда вы запускаете вызов, селектор не сможет изменить переменную, на которую указывает указатель ошибки.Другими словами, это будет похоже на вызов [myData writeToFile:string options:dataOptions error:NULL].

Итак, вы также захотите объявить переменную NSError и назначить ее адрес в качестве переменной, на которую должен указывать ваш errorPointer:

NSError *error;
NSError **errorPointer = &error;

Теперь вы можете передать errorPointer в качестве аргумента, и вы сможете проверить его позже, если возникла проблема при вызове метода.Прочтите этот пост на NSInvocation , чтобы получить немного больше помощи (совет по поводу Марка Далримпла для указания на пост в блоге)

Важно также понимать, чтообласть действия должна учитываться для аргументов, которые вы создаете и передаете в ваш вызов.Взгляните на похожий вопрос, который я задал здесь .

2 голосов
/ 16 апреля 2013

Принятый ответ от edelaney05 был отличным, но я думаю, что для ARC требуется небольшая настройка.(Я пока не могу добавлять комментарии, поэтому создаю новый ответ для документа, который нашел)

Как есть, я получил ошибку компиляции: «Указатель на неконстантный тип« NSError * »без явного владельца"

Я исследовал это и обнаружил, что мне нужно:

 NSError * __autoreleasing error = nil;
 NSError * __autoreleasing *errorPointer = &error;

Ссылки, которые привели меня к этому ответу:

NSInvocation & NSError - __autoleaseing и сбой памяти

Автоматический подсчет ссылок: указатель на неконстантный тип 'NSError *' без явного владения

http://developer.apple.com/library/ios/#releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html

"__ autoreleasingиспользуется для обозначения аргументов, которые передаются по ссылке (id *) и автоматически высвобождаются при возврате. "

0 голосов
/ 11 мая 2012

Тип параметра NSError **, который вы получаете, взяв адрес NSError *, в который вы хотите записать ошибку. Чтобы установить аргумент в NSInvocation, вам нужно передать адрес значения аргумента в setArgument:, поэтому вам нужно поместить NSError ** в переменную (я называю это errPointer здесь), и возьмите адрес того (который будет NSError ***), чтобы перейти к setArgument:. Вам не нужна переменная errPointer впоследствии.

NSError *err = nil;
NSError **errPointer = &err;
[invocation setArgument:&errPointer atIndex:4];
...