2

I am trying to create NSInvocationOperation so that it should call object's method with params

- (void) getImages: (NSRange) bounds
{
    NSOperationQueue *queue = [NSOperationQueue new];
    NSArray * params = [NSArray arrayWithObjects:
          [[NSNumber alloc] initWithInt: bounds.location],
          [[NSNumber alloc] initWithInt: bounds.length]];
    NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self
                   selector:@selector(loadImagesWithOperation)
                     object:params];

    [queue addOperation:operation];
    [operation release];

}

- (void) loadImagesWithOperation:(NSArray*)bounds {
 NSLog(@"loadImagesWithOperation");
}

This code crashes with EXC_BAD_ACCESS. If I change definition of function to be called to this

- (void) loadImagesWithOperation {
 NSLog(@"loadImagesWithOperation");
}

everything becomes fine. I have tried to use different syntax in @selector's code block like @selector(loadImagesWithOperation:) and @selector(loadImagesWithOperation:bounds:), but had not succeeded.

What is the right way to define selector and function with params?

Thanks.

Jacob Relkin
  • 161,348
  • 33
  • 346
  • 320
duganets
  • 1,853
  • 5
  • 20
  • 31

2 Answers2

5

The correct way to define a SEL that takes arguments is to use a colon (":") character for each argument, so in your case, the selector would look like this:

@selector(loadImagesWithOperation:)

So, your NSInvocationOperation object should be initialized like this:

NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self
               selector:@selector(loadImagesWithOperation:)
                 object:params];

Oh, and just as a side note, you have memory leaks on the initialization of your NSArray in getImages::

NSArray * params = [NSArray arrayWithObjects:
      [[NSNumber alloc] initWithInt: bounds.location],
      [[NSNumber alloc] initWithInt: bounds.length]];

This adds objects that already have a retainCount of 1 because you're using +alloc, so when they are added to the NSArray, they get sent the -retain message, thereby incrementing the retainCount to 2.

When this NSArray is deallocated, these objects will not be deallocated because their retainCount will be 1, not 0.

There are three solutions to this problem:

  1. Send the autorelease message to each of these objects before they are added to the NSArray.
  2. Use NSNumber's numberWithInt: class method to obtain an autoreleased NSNumber object.
  3. Create references to these NSNumber objects, add them to the NSArray, then upon addition, send them the -release message.
Jacob Relkin
  • 161,348
  • 33
  • 346
  • 320
  • Thanks for quick answer, Jacob, but under some circumstances this code doesn't work. Placing colon after function name in selector still cause EXC_BAD_ACCESS. I got stuck. – duganets Jan 24 '11 at 23:03
  • Ewww... `retainCount`. Correct that it is a leak, but the absolute retain counts might differ and aren't worth mentioning. – bbum Jan 26 '11 at 15:54
  • Thanks to all for hint. It was memory issues that caused crash and lack of any experience with memory management rules. I'am working to improve that. – duganets Feb 07 '11 at 08:15
3

everything becomes fine. I have tried to use different syntax in @selector's code block like @selector(loadImagesWithOperation:) and @selector(loadImagesWithOperation:bounds:), but had not succeeded.

initWithTarget:selector:object: takes a selector that can accept exactly 0 or 1 arguments, no more (not two). That one argument must be an object. If you need more arguments, either use blocks or refactor your code (passing an array with the rest of the objects within is a potential solution, yes -- kinda like what you are doing in that code (though note the memory leaks).

The crash is unrelated to the code you have shown. Post the crash.

Note also that methods with get at the head have a very specific meaning in Cocoa/iOS and are not used for this kind of pattern. I would suggest loadImages.

bbum
  • 162,346
  • 23
  • 271
  • 359