-3

I am new to Objective-C and iOS (3 days old). I am trying to work around the warning 'PerformSelector may cause a leak because its selector is unknown'

SEL _mySelector;
id _myTarget;
NSMutableData * _myJsonData ;
[_responseTarget performSelector:_responseSelector withObject:_myJsonData]; // Warning here

I have changed it to this

    IMP imp = [_responseTarget methodForSelector:[_responseSelector withObject:_myJsonData]]; //Errors!
    void (*func)(id, SEL) = (void *)imp;
    func(_myTarget, _mySelector);

It errors with "Bad receiver type 'SEL'"

I would appreciate your help.

Paulw11
  • 95,291
  • 12
  • 135
  • 153

1 Answers1

1

First the warning occurs as the automatic memory management (ARC) needs to know the type and ownership of the result of a method call in order to determine how to manage any returned references to objects.

Using performSelector with a variable selector value does not provide this information - selector values (of type SEL) in Objective C do not carry type information. Without the type information the safe assumption is to do no memory management, but this might cause a leak, and so the warning.

In your case it seems you are expecting a selector with a return type of void, and if nothing is being returned nothing can be leaked.

Your attempt to avoid this by getting a type function pointer to the method and calling that will work, except you made a mistake. The error "Bad receiver type 'SEL'" is referring to the method call [_responseSelector withObject:_myJsonData] - a selector is not an object and you can't send it messages! What you appear to be trying to do is supply one argument (_myJsonData) to the method pre-bound into the function pointer, and the other two arguments (_myTarget, _mySelector) at the point of call. Why you should want this is unclear (maybe you're a Haskell user?).

The solution is simple, don't try to pre-bind the argument:

IMP imp = [_myTarget methodForSelector:_mySelector];
void (*func)(id, SEL, NSMutableData *) = (void *)imp;
func(_myTarget, _mySelector, _myJsonData);

However there is a different approach possible: as you know you are returning nothing (void) you can instruct the compiler to simply turn off the warning for the performSelector call:

    // avoid warning on performSelector - return is void so leak not possible
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
    (void)[_myTarget performSelector:_mySelector withObject:_myJsonData];
#pragma clang diagnostic pop

HTH

CRD
  • 50,500
  • 4
  • 64
  • 80
  • Thanks a billion! Very well understood. Yes, Heskell background - but in this case more of a 'stupid' background not realising a selector is not an object. – user3478634 Apr 08 '14 at 20:07