简体   繁体   中英

NSInvocation returning nil

Does anyone know how can I set the argument of NSInvocation to be nil ? I am trying to use OCMock and I would like this expectation to return nil. The problem is that I need to do something else when the method is called, as you can see in the example, that´s why I am not doing andReturn:nil

I want to do this:

[[[myObject stub] andDo:^(NSInvocation *inv) {
   [inv setReturnValue:Nil];
   [inv invoke];
   [self notify:kXCTUnitWaitStatusSuccess]; //Code that I need to execute
}] myMethod:OCMOCK_ANY];

But I get an error:

 *** Terminating app due to uncaught exception 
 'NSInvalidArgumentException', reason: '-[NSInvocation setArgument:atIndex:]: 
 NULL address argument'

Anyone knows if there is another way to set that to nil? or if it is imposible?

First, your code doesn't really make sense. You are supposed to set the arguments of an invocation before invoking the invocation, the method called will read the arguments you gave it, and set the return value, and you can then read the return value after invoking the invocation. It makes no sense for you to set the return value before invoking it, because the "return value" is by definition the thing "returned" as a result of the invocation, and will be set at the end of the invocation, overwriting whatever you set before.

To address the error you're getting, for all the getArgument , setArgument , getReturnValue , setReturnValue functions you need to pass a pointer to a buffer where the value is to be read or written. This is because arguments and returns values can be various C types, of various sizes, so there is no way that you can pass it directly. In this case, it seems like the value to be read/written is an object pointer, so you need to create a variable of object-pointer type, set to the value you want (in the case you are setting), and then you pass a pointer to this variable to getArgument / setArgument / getReturnValue / setReturnValue .

@newacct made the point and he is completely right. You cannot set the returning value of an invocation before actually invoking it. What I did for getting " nil " as the result of the invocation was to modify the arguments of the invocation so the code that will be called by the invocation generate nil as a result. Let me explain it with an example:

- (void)viewDidLoad {
  NSString *arg = @"HelloWorld";

  NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[self methodSignatureForSelector:@selector(isHelloWorld:)]];
  [invocation setSelector:@selector(isHelloWorld:)];
  [invocation setTarget:self];
  [invocation setArgument:&arg atIndex:2];

  NSString *result1 = nil;
  [invocation invoke];
  [invocation getReturnValue:&result1];

  NSString *result2 = [self resultOfModifiedInvocation:invocation];

  NSLog(@"result 1: %@",result1);
  NSLog(@"result 2: %@",result2);
}

- (NSString *) resultOfModifiedInvocation:(NSInvocation *) invocation {
  NSString *aString = @"NoWorld";
  [invocation setArgument:&aString atIndex:2];

  [invocation invoke];
  [invocation getReturnValue:&aString];

  return aString;
}


- (NSString *) isHelloWorld:(NSString *) aString{
  if([aString isEqualToString:@"HelloWorld"])
    return aString;
  else
    return nil;
}

The method isHelloWorld: is supposed to return @"HelloWorld" since what we are sending in the invocation is right. This actually happens the first time you invoke the invocation since the argument has not been modified. Ih the other hand, by calling resultOfModifiedInvocation: the arguments of the invocation gets modified and then the result of the invocation is different.

This is the output of the example:

  > result 1: HelloWorld
  > result 2: (null)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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