简体   繁体   English

NSInvocation nil参数

[英]NSInvocation nil argument

How do I (or can I even) pass a nil argument to an NSInvocation object? 我如何(或者甚至可以)将nil参数传递给NSInvocation对象?

I tried to do this: 我试着这样做:

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

The first approach will crash with this message: 第一种方法会因此消息而崩溃:

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

The second approach will crash with this message: 第二种方法会因此消息而崩溃:

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

Thanks in advance for any help! 在此先感谢您的帮助!

Yes, you can pass nil arguments. 是的,你可以传递零参数。 More precisely, you can pass a valid pointer whose contents are nil. 更确切地说,您可以传递内容为nil的有效指针。

I haven't been able to reproduce your particular problem. 我无法重现您的特定问题。 Here's the code I've used to test it. 这是我用来测试它的代码。 There's probably something else in your program that's causing the error. 你的程序中可能还有其他东西导致错误。

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

I've also tested it without using NSInvocationOperation and sending -retainArguments directly, since that's what seems to be triggering your error. 我还测试了它,没有使用NSInvocationOperation并直接发送-retainArguments,因为这似乎是触发你的错误。

For the record, your second approach won't work since -[NSInvocation setArgument:atIndex:] expects a valid memory address pointing to a buffer which will be copied. 对于记录,您的第二种方法将无法工作,因为 - [NSInvocation setArgument:atIndex:]需要一个指向将被复制的缓冲区的有效内存地址。 In the case of object arguments, the buffer must contain the address of the object. 对于对象参数,缓冲区必须包含对象的地址。 The address of the object can be zero but the address of the buffer must be valid. 对象的地址可以为零,但缓冲区的地址必须有效。

You can accomplish this by simply not calling setArgument:atIndex: for the argument index that you wish to remain nil. 你可以通过简单地不调用setArgument:atIndex:来实现这一点,因为你希望保持nil的参数索引。

However, if you have already set that argument to something besides nil, and wish to change it back to nil, a few quick tests seem to indicate that you just can't. 但是,如果你已经将该参数设置为除了nil之外的某个东西,并希望将其更改为nil,那么一些快速测试似乎表明你不能。 I could be wrong, but it looks like you would have to create a new invocation object and manually copy all the desired values into it, minus the argument that you wish to remain nil. 我可能是错的,但看起来你必须创建一个新的调用对象并手动将所有需要的值复制到其中,减去你希望保持为零的参数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM