i have implemented UIImage Category...and i am trying to call a method from my viewcontroller..strangely i am getting below shown warning
can anyone please answer why i am getting this warning and how to avoid that
It looks like the compiler doesn't know if it needs to release the value returned by the selector. So I'm guessing you have ARC enabled, or maybe the compiler is checking this anyway as part of the static analysis stuff.
The selector may return a +1 retained object, or an autoreleased object. There is no way to know this at compile time so the compiler is giving you this warning.
Generally you should not get objects from selectors like this. The better solution would be with a strongly typed delegate interface where the memory semantics are clearer.
Related
Before ARC, I had an "X may not respond to xxx" warning, which is a pretty harmless warning which does not prevent it from compiling. Now, I am trying to convert my project to ARC, and I have an "No visible #interface for X declares the selector xxx" error, which prevents it from compiling.
I know exactly what I am doing, and why the warning was there, and I can tell you that the program is correct. Previously, the compiler compiled it with no problem, and should not now stop it from compiling.
It is true that class X's interface does not declare that selector, but X is a class that dynamically handles any message with any selector sent to it, using forwardInvocation: (that is one of the beautiful things about Objective-C), so its interface cannot possibly declare all the selectors that can be called on it. And the selector is declared somewhere, just not on X.
I know exactly what I am doing, and why the warning was there, and I can tell you that the program is correct.
OK -- Just use objc_msgSend et al. directly if you want to do the compiler's work.
It is true that class X's interface does not declare that selector, but X is a class that dynamically handles any message with any selector sent to it, using forwardInvocation: (that is one of the beautiful things about Objective-C), so its interface cannot possibly declare all the selectors that can be called on it. And the selector is declared somewhere, just not on X.
If it's too tedious to declare but not tedious enough to use in messaging that seems to contradict your program's use of the selector… Sounds like the dangerous territory of generated code with significant human intervention.
Perhaps you should consider declaring a protocol so the compiler can at least set the message calls up correctly for you -- and if you change or break something, it has a chance to adapt or notify you.
I'm not certain, but I believe under ARC it's more important that the compiler can see a method signature, because it needs to know what memory management is needed. So you'll either need to:
Declare the methods you're using via one of the normal methods (i.e. ideally on the real receiver, but if nothing else as a category, even if only on NSObject).
Do things manually via NSInvocation or some other similar means, taking full responsibility for memory management (which can be tricky, as you'll have to bridge to and from ARC).
Update: I just checked the clang source, and this is indeed the case - it needs the signature when using ARC. It's not just trying to be mean. :)
It is true that class X's interface does not declare that selector, but X is a class that dynamically handles any message with any selector sent to it, using forwardInvocation: (that is one of the beautiful things about Objective-C), so its interface cannot possibly declare all the selectors that can be called on it. And the selector is declared somewhere, just not on X.
Cast to id if you want to discard the static type information. Or if your object is a proxy for another class, maybe cast to that class.
So long as the method is declared somewhere in a header (which needed to be the case anyway), and there is no ambiguity with argument types, this should fix the error.
If you're interested in why this only is an issue with ARC enabled, check the answer to this question I asked: Why is 'no known method for selector x' a hard error under ARC?
I am trying to have a fairly dynamic api for the level class of my game... basically, I just have a bunch of class methods optionsForLevel1, optionsForLevel2, ...etc, that all return a dictionary object with things like how much time the level should have, how many bonus points, the level's name, etc...
In my actual game object, when it's time to advance levels, it calls a method on the level object which does:
+(NSDictionary*)performClassSelectorForLevel:(int)identifier {
SEL sel = NSSelectorFromString([NSString stringWithFormat:#"optionsForLevel%d", identifier]);
return [self performSelector:sel];
}
This gives me a warning: PerformSelector may cause a leak because its selector is unknown.
...
How can I resolve this warning?
This is interesting. You can't. Not in my experience. Simply this is a warning, not an error, this "may" cause a leak.
When using performSelector: it's your responsibility to make sure it doesn't leak, of course the compiler doesn't know the selector in the NSString, it's unknown at compile time, as it will have its value assigned at runtime.
You can suppress this warning, but it's okay to ignore
Check out this answer for more details: PerformSelector warning
The warning is generated by the compiler because ARC needs to know what kind of objects may be returned by that method to make sure memory is not mismanaged.
More details on this here: performSelector may cause a leak because its selector is unknown.
Here is the situation:
I have created a custom view class with UITextView as its member. I make textView as a first responder after some event occurs.
#inteface MyCustomView : UIView{
UITextView* textView;
}
- (void) doSomething;
#end
During program execution I send [doSomething] message to MyCustomView's instance.
[myCustomViewInstance doSomething];
What happens is very interesting, the program crashes by complaining that UITextView:doSomething is unrecognized selector.
Why is the program calling doSomething on UITextView (its member variable) instead of MyCustomView's instance.
What could be possibly wrong here ? (of course this is a canonical version of what I am doing but I don't understand in any logical error scenario this could be true unless something is messed up at compiler level)
What do you think I should investigate further ?
First, Objective-C doesn't have "member" variables, it has instance variables. Minor thing; but terminology does matter.
Secondly, the crash is happening because myCustomViewInstance is pointing to an instance of UITextView and not your subclass. This may be because you made such an assignment inadvertently or it may be because you have an over-release issue and it so happens that said variable ends up pointing to the wrong object by coincidence.
Finally, while there are certainly compiler bugs, it is exceedingly unlikely that such straightforward code would unveil a heretofore unknown compiler bug. The compiler you are using is the very same one that is used to compile the umpteen millions of lines of code of the OS; such a simple bug would very likely means no apps would work or, quite likely, the device wouldn't even boot.
That assumes that said line of code is actually what is crashing.
For years I've been following a great pattern called Target-Action which goes like this:
An object calls a specified selector on a specified target object when the time comes to call. This is very useful in lots of different cases where you need a simple callback to an arbitrary method.
Here's an example:
- (void)itemLoaded {
[specifiedReceiver performSelector:specifiedSelector];
}
Under ARC it now turns out that doing something like this all of a sudden became dangerous.
Xcode throws a warning that goes like this:
PerformSelector may cause a leak because its selector is unknown
Of course the selector is unknown since as part of the Target-Action design pattern you can specify whatever selector you want in order to get a call when something interesting happens.
What bugs me most about this warning is that it says there can be a potential memory leak. From my understanding ARC doesn't bend the memory management rules but instead simply automates the insertion of retain/release/autorelease messages at the right locations.
Another thing to note here: -performSelector: does have an id return value. ARC analyzes method signatures to figure out through application of naming conventions if the method returns a +1 retain count object or not. In this case ARC doesn't know if the selector is a -newFooBar factory or simply calling an unsuspicious worker method (which is almost always the case with Target-Action anyways). Actually ARC should have recognized that I don't expect a return value, and therefore forget about any potential +1 retain counted return value. Looking at it from that point of view I can see where ARC is coming from, but still there is too much uncertainty about what this really means in practice.
Does that now mean under ARC something can go wrong which would never happen without ARC? I don't see how this could produce a memory leak. Can someone give examples of situations in which this is dangerous to do, and how exactly a leak is created in that case?
I really googled the hell out of the internet but didn't find any site explaining why.
The problem with performSelector is that ARC doesn't know what the selector which will performed, does. Consider the following:
id anotherObject1 = [someObject performSelector:#selector(copy)];
id anotherObject2 = [someObject performSelector:#selector(giveMeAnotherNonRetainedObject)];
Now, how can ARC know that the first returns an object with a retain count of 1 but the second returns an object which is autoreleased? (I'm just defining a method called giveMeAnotherNonRetainedObject here which returns something autoreleased). If it didn't add in any releases then anotherObject1 would leak here.
Obviously in my example the selectors to be performed are actually known, but imagine that they were chosen at run time. ARC really could not do its job of putting in the right number of retains or releases here because it simply doesn't know what the selector is going to do. You're right that ARC is not bending any rules and it's just adding in the correct memory management calls for you, but that's precisely the thing it can't do here.
You're right that the fact you're ignoring the return value means that it's going to be OK, but in general ARC is just being picky and warning. But I guess that's why it's a warning and not an error.
Edit:
If you're really sure your code is ok, you could just hide the warning like so:
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[specifiedReceiver performSelector:specifiedSelector];
#pragma clang diagnostic pop
The warning should read like this:
PerformSelector may cause a leak because its selector is unknown. ARC doesn't know if the returned id has a +1 retain count or not, and therefore can't properly manage the memory of the returned object.
Unfortunately, it's just the first sentence.
Now the solution:
If you receive a return value from a -performSelector method, you can't do anything about the warning in code, except ignoring it.
NSArray *linkedNodes = [startNode performSelector:nodesArrayAccessor];
Your best bet is this:
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
NSArray *linkedNodes = [startNode performSelector:nodesArrayAccessor];
#pragma clang diagnostic pop
Same goes for the case in my initial question, where I completely ignore the return value. ARC should be intelligent enough to see that I don't care about the returned id, and therefore the anonymous selector is almost guaranteed not to be a factory, convenience constructor or whatsoever. Unfortunately ARC is not, so the same rule applies. Ignore the warning.
It can also be done for the whole project by setting the -Wno-arc-performSelector-leaks compiler flag under "Other Warning Flags" in project build settings.
Alternatively, you can surpress the warning on a per-file basis when you add that flag under Your Target > "Build Phases" > "Compile Sources" on the right-hand side next to the desired file.
All three solutions are very messy IMHO so I hope someone comes up with a better one.
As described above you get that warning because the compiler does not know where (or if) to put the retain/release of the performSelector: return value.
But note that if you use [someObject performSelector:#selector(selectorName)] it will not generate warnings (at least in Xcode 4.5 with llvm 4.1) because the exact selector is easy to be determined (you set it explicitly) and that's why compiler is able to put the retain/releases in the correct place.
That's why you will get warning only if you pass the selector using SEL pointer because in that case the compiler is unable to determine in all case what to do. So using the following
SEL s = nil;
if(condition1) SEL = #selector(sel1)
else SEL = #selector(sel2)
[self performSelector:s];
will generate warning. But refactoring it to be:
if(condition1) [self performSelector:#selector(sel1)]
else [self performSelector:#selector(sel2)]
will not generate any warnings
ARC is throwing the warning because it can't guarantee that the selector isn't creating an object it doesn't know about. You could theoretically receive something from that method that ARC can't handle:
id objectA = [someObject performSelector:#selector(createObjectA)];
Maybe someday it can, but right now it can't. (Note if it does know the object (it's not an id) it doesn't throw this warning).
If you're trying to simply execute a method without receiving an object back from it, I recommend using objc_msgSend. But you've gotta include in your class:
#include <objc/message.h>
objc_msgSend(someObject, action);
I would like to know witch is the best practice to test if void pointer is actually an objective C object pointer (NSObject*)...
- (id)initWithExecPath:(NSString*)executePath withArgs:(NSArray*)args identifier:(NSString*)identifierString contextInfo:(void*)contextInfo {
// I would like to check here if contextInfo is an NSObject
}
Thanks...
Check out this post from the CocoaWithLove site:
In this post, I look at an approach for testing if an arbitrary
pointer is a pointer to a valid Objective-C object. The result from
the test is not absolutely accurate and can interfere with gdb
debugging if the pointer isn't a valid memory location, so this is not
something you'd want to do often (and certainly not in production
code). But it can be a handy debugging tool for when you're staring
blindly at memory you didn't allocate.
The answer is that no you can't provide a general test for "is an Objective-C object". Any such test would have to examine the internal structure of an object and is therefore fragile by definition. There is also the possibility of being handed a random piece of memory that looks like an Objective-C object but isn't. e.g. a recently deallocated object.
There is no reliable way to determine this. Also, any API that takes a context pointer shouldn't care what it is or what it points to, it shouldn't do anything with it other than pass it back to the caller as context.
Perhaps you are asking the wrong question; what exactly do you want to do once you know it is an NSObject?