2010-12-29 19 views
8

Come posso (o posso anche) passare un argomento nil a un oggetto NSInvocation?NSInvocation nil argument

Ho provato a fare questo:

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]; 

Il primo approccio andrà in crash con questo messaggio:

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 

Il secondo approccio andrà in crash con questo messaggio:

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

Grazie in anticipo per qualsiasi aiuto!

risposta

9

Sì, è possibile passare argomenti nil. Più precisamente, puoi passare un puntatore valido il cui contenuto è nullo.

Non sono stato in grado di riprodurre il problema specifico. Ecco il codice che ho usato per testarlo. Probabilmente c'è qualcos'altro nel tuo programma che sta causando l'errore.

#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; 
} 

Ho anche provato senza usare NSInvocationOperation e l'invio direttamente -retainArguments, dato che è quello che sembra essere innescando il vostro errore.

Per la cronologia, il secondo approccio non funzionerà poiché - [NSInvocation setArgument: atIndex:] prevede un indirizzo di memoria valido che punta a un buffer che verrà copiato. Nel caso degli argomenti oggetto, il buffer deve contenere l'indirizzo dell'oggetto. L'indirizzo dell'oggetto può essere zero ma l'indirizzo del buffer deve essere valido.

+0

Hai ragione. Il problema non ha nulla a che fare con l'impostazione/non impostare gli argomenti con valori nulli. Uno dei miei argomenti non-nil è un doppio array primitivo e ho dimenticato di inserirlo in un doppio puntatore prima di passarlo nell'oggetto di invocazione. –

3

È possibile eseguire questa operazione semplicemente non chiamando setArgument:atIndex: per l'indice argomento che si desidera rimanere nullo.

Tuttavia, se hai già impostato quell'argomento su qualcosa diverso da zero e desideri reimpostarlo su zero, alcuni test rapidi sembrano indicare che non è possibile. Potrei sbagliarmi, ma sembra che tu debba creare un nuovo oggetto di invocazione e copiare manualmente tutti i valori desiderati in esso, meno l'argomento che desideri rimanere nullo.

+0

Hai ragione. Ho dimenticato di dire che ho pensato, e in realtà ho provato, semplicemente non chiamando 'setArgument: atIndex:' per il nulla arg. Il problema non era affatto collegato ai miei argomenti nil. –