NSInvocation ноль аргумент

Как я (или я могу даже) передать нулевой аргумент объекту NSInvocation?

Я пытался сделать это:

NSMethodSignature* signature = [AClass instanceMethodSignatureForSelector:@selector(aMethod:theOtherArg:)];
NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: signature];

[invocation setTarget: aTargetObj];
[invocation setSelector: @selector(aMethod:theOtherArg:)];

/* I've tried both this way */
AnObj* arg1 = nil;
AnotherObj* arg2 = nil;
[invocation setArgument: &arg1 atIndex:2];
[invocation setArgument: &arg2 atIndex:3];

/* and this way */
//[invocation setArgument: nil atIndex:2];
//[invocation setArgument: nil atIndex:3];

NSInvocationOperation* operation = [[NSInvocationOperation alloc] initWithInvocation:invocation];
//opQueue is an NSOperationQueue object
[opQueue addOperation:operation];

Первый подход завершится с этим сообщением:

Thread 0 Crashed:
0   libSystem.B.dylib              0x927c1f10 strlen + 16
1   com.apple.CoreFoundation       0x92dd1654 __NSI3 + 500
2   com.apple.CoreFoundation       0x92dd1994 -[NSInvocation retainArguments] + 132
3   com.apple.Foundation           0x96a50c5e -[NSInvocationOperation initWithInvocation:] + 78

Второй подход завершится с этим сообщением:

Error: Exiting due to caught object *** -[NSInvocation setArgument:atIndex:]: NULL address argument

Заранее благодарю за любую помощь!

2 ответа

Решение

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

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

#import <Foundation/Foundation.h>

@interface Person : NSObject {
    NSString *name;
    NSUInteger age;
}
- (void)setName:(NSString *)personName age:(NSNumber *)personAge;
@end

@implementation Person
- (void)setName:(NSString *)personName age:(NSNumber *)personAge {
    NSLog(@"setName:%@ age:%@", personName, personAge);
    name = [personName copy];
    age = [personAge unsignedIntegerValue];
}
@end

int main() {
    NSAutoreleasePool *pool = [NSAutoreleasePool new];            
    Person *person = [Person new];

    SEL sel = @selector(setName:age:);

    NSMethodSignature *sig = [Person instanceMethodSignatureForSelector:sel];
    NSInvocation *inv = [NSInvocation invocationWithMethodSignature:sig];

    [inv setTarget:person];
    [inv setSelector:sel];

    NSString *name = nil;
    NSNumber *age = nil;

    [inv setArgument:&name atIndex:2];
    [inv setArgument:&age atIndex:3];

    // [inv retainArguments];
    // [inv invoke];

    NSInvocationOperation *op = [[[NSInvocationOperation alloc] initWithInvocation:inv] autorelease];
    NSOperationQueue *queue = [NSOperationQueue new];
    [queue addOperation:op];

    [pool release];
    return 0;
}

Я также проверил это без использования NSInvocationOperation и прямой отправки -retainArguments, так как это, кажется, вызывает вашу ошибку.

Для записи, ваш второй подход не будет работать, поскольку -[NSInvocation setArgument:atIndex:] ожидает действительный адрес памяти, указывающий на буфер, который будет скопирован. В случае аргументов объекта буфер должен содержать адрес объекта. Адрес объекта может быть нулевым, но адрес буфера должен быть действительным.

Вы можете сделать это, просто не звоня setArgument:atIndex: для индекса аргумента, который вы хотите оставить ноль.

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

Другие вопросы по тегам