I have this inside a class
[delegate performSelector:#selector(doStuff:) withObject:myObject afterDelay:2.0];
and I am having this error
warning:
'-performSelector:withObject:afterDelay:'
not found in protocol(s)
I cannot figure out what may be wrong.
any clues?
thanks.
Your problem is that you've declared your delegate instance variable as:
id<SomeProtocol> delegate;
Right? Well, that means that the compile-time checker is only going to look for methods in the <SomeProtocol> protocol. However, performSelector:withObject:afterDelay: is declared on NSObject. This means that you should declare the ivar as:
NSObject<SomeProtocol> * delegate;
This is saying that it must be an NSObject that conforms to <SomeProtocol>, as opposed to any object that conforms to <SomeProtocol>. This should get rid of your warning, and you don't have to do any casting.
Try casting the delegate to its class' type first, then invoke performSelector:withObject:afterDelay:
[(SomeClass *) delegate performSelector:#selector(doStuff:) withObject:myObject afterDelay:2.0];
Assuming that your delegate is of type id, you need to tell the runtime that the object in fact does inherit from NSObject (where the performSelector:withObject:afterDelay: method is defined) by casting it to it's class' type.
Although the NSObject * cast Dave brought up will work, there's a cleaner alternate way that lets people use protocols as they would expect - you can have the protocol itself declare it supports the NSObject protocol.
NSObject is not just an implementation but also a protocol that includes all of the performSelector: method variants. So you can simply declare in your protocol that you support NSObject like you would any other class supporting a protocol:
#protocol MyProtocol <NSObject>
And the compiler warnings will vanish (assuming you have imported the protocol definition).
Note that this does mean going forward anyone that declares support of your protocol would pretty much have to be an NSObject or inherit a lot of methods. But all classes used in iPhone programming are derived from NSObject due to practical considerations, so that's generally not an issue.
EDIT:
It turns out the -performSelector:withObject:afterDelay: is not in the NSObject protocol (the ones without the delay are). Because it's still nicer to everyone using your protocol if they can just use id to reference a protocol type, I'd still use a protocol to solve this - but you'd have to declare an extension to the NSObject protocol yourself. So in the header for your file you could add something like:
#protocol MyProtocolNSObjectExtras <NSObject>
- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay;
#end
#protocol MyProtocol <NSObjectExtras>
....
#end
Then you get all the same benefits as I described previously.
You need to cast the delegate object to the actual class you are working in order to have the methods. Seen the delegate only can only show the methods defined in the protocol. performSelector:withObject: is not a method defined in the protocol.
[(CLASS*)delegate performSelector:#selector(doStuff:) withObject:myObject afterDelay:2.0];
[NSTimer scheduledTimerWithTimeInterval:2
target:self
selector:#selector(doStuff)
userInfo:nil
repeats:NO];
Try that assuming you just want a timer
Related
I have a class that does some generic code for Writing to a Database. Bring up the popovers, and controls, etc. Though there are many types of elements that I can write out to the database, each sub-class needs to have its own -(void) writeTagValue selector to implement the element's write.
The base-class has a selector that does the call to self.writeTagValue though since the base class does not really do any writing, its -(void) writeElement selector is empty with an abort(); in it.
I've implemented a protocol in the base class.h
#protocol IoUISEWriteAnimation <NSObject>
-(void) writeTagValue;
-(IBAction)saWriteValue:(NSNotification *)notification;
#end
added the protocol to the Sub-classes and now if the sub-classes don't define the selectors, I get compiler warnings.
What I want to know is, is there a way to remove the empty -(void) writeElement selector in the base class?
You can do something like this:
#protocol MyProtocol<NSObject>
#required
-(void) myRequiredMethod;
#optional
-(void) myOptionalMethod;
#end
And when you need to call an optional method, you do something like this:
if ([delegate respondsToSelector:#selector(myOptionalMethod)])
[delegate myOptionalMethod];
else
// abort, or ignore.
So long as the implementation class implement the required methods in the protocol, your base class does not need an empty implementation of that method. However, since it's required, the base class cannot specify that it implements the protocol.
You're on the right path.
retain is declared in NSObject protocol.
Therefore NSObject class and NSProxy class implement it.
yet both NSProxy and NSObject classes both have an alloc.
Why isnt alloc declared in NSObject protocol?
Side question:
NSObject protocol is also used to stored the class version of a method where as the instance method is in NSObject class. Is there anything to stop both class and instance being declared in the NSObject protocol. Why split them up?
#protocol NSCopying
- (id)copyWithZone:(NSZone *)zone; //INSTANCE METHOD version of copyWithZone
#end
#interface NSObject <NSObject> {
Class isa;
}
...
+ (id)copyWithZone:(NSZone *)zone; //CLASS METHOD version of copyWithZone
Cheers
I think this is determined by what is required by Objective-C, and what is required by implementation.
In order to create an object, you need a way to allocate it. This is done by the alloc method. Since this is required to use objective-c, it is implied that all root objects should implement it. However, memory management does not have to be done through reference counting. You could use garbage collection instead. Because of this, the retain method is not required to use objective-c. Apple's implementation created the retain method as a form of memory management. They wanted to ensure that all objects had it available, so they added it to the NSObject protocol. All root classes in Cocoa are supposed to conform to that protocol, so they should all have a retain method.
A class can conform to the NSCopying protocol to show that instances of that class can be copied. Normally, you wouldn't want to copy a class, so a class method isn't defined there. However, sometimes you don't know whether an object is a class or instance, but calling conformsToProtocol: will return the same value either way. By making an identically named class method, you know that it is safe to call copyWithZone: even if you don't know whether you have an instance or class.
I have an NSOperation that wraps some web service functionality. The NSOperation has a delegate that is to be messaged when the operation is over.
As the NSOperation lives on a different thread I have to make the call like this:
[delegate performSelectorOnMainThread:#selector(getDealersIDSuccess:) withObject:result waitUntilDone:YES];
It works just fine, but it gives me a warning:
warning:
'-performSelectorOnMainThread:withObject:waitUntilDone:'
not found in protocol(s)
I completely agree with the compiler on this one, it sees a delegate, it checks the protocol, it finds no declaration of a performSelector method.
My question is: can I remove the warning by making this call in a different manner?
My two guesses are that I could (1) write a method called
- (void) callDelegateMethodOnMainThred {
[delegate getDealersIDSuccess:result]
}
and call that through performSelectorOnMainThread, but I find that solution to be cumbersome and an extra, hard to read, step on top of the delegation.
The second solution could be to cast the delegate to the type of my parent object inside the selector, but that is just plain crazy and goes against the delegate encapsulation pattern.
I would really appreciate a third solution from someone with a better understanding of the language:)
Thank you in advance.
EDIT: Added delegate declaration:
id <ISDealersIDDelegate> delegate;
I declare my delegate as id. The delegate it self extends UIViewController.
I could see that declaring it NSObject would work.
performSelectorOnMainThread:withObject:waitUntilDone: method is declared in NSObject class. If your delegate object inherits from NSObject you can declare it as
NSObject<MyDelegateProtocol> *delegate;
So compiler will know that delegate responds to NSObject's methods and won't issue a warning.
It might be even a better solution not call performSelectorOnMainThread: on a delegate or other protocol implementation.
Make it the responsibility of the delegate/receiver to determine if it needs to do things on the main thread.
[delegate performSelector:#selector(delegateAction:)
withObject:actionData];
Delegate implementation
- (void)delegateAction:(NSData*)actionData
{
[self performSelectorOnMainThread:#selector(updateUIForAction:)
withObject:actionData
waitUntilDone:NO];
}
- (void)updateUIForAction:(NSData*)actionData
{
// Update your UI objects here
}
It might look like more code, but the responsibility is in the right place now
Actually on iOS 4 I prefer using NSNotifications and Observers (with Blocks) to perform updates on the mainthread.
- (id)addObserverForName:(NSString *)name object:(id)obj queue:(NSOperationQueue *)queue usingBlock:(void (^)(NSNotification *))block
I wrote down my design here.
1) Declare your delegate's protocol to extend the NSObject protocol in the .h file
#protocol YourDelegateProtocol <NSObject>
2) Cast to NSObject in your call
[(NSObject*)delegate performSelectorOnMainThread:#selector(getDealersIDSuccess:) withObject:result waitUntilDone:YES];
I definitely recommend number (1).
This could be me doing the design pattern wrong.
I'm implementing asynchronous delegation in an application that uses NSURLConnection. An object wraps the NSURLConnection and handles its delegated messages; that works fine. Now I'm defining my own delegates in the object that uses it (NSURLConnection messages ConnectionWrapper, ConnectionWrapper messages NeedsToUseConnection, you get the idea), and that works as well, however, Xcode emits this warning:
No '-request:finishedWithResult' method found
This is, presumably, because I'm declaring the delegate I'm calling like this:
id<NSObject> delegate;
...and Xcode is checking what NSObject declares in the Foundation framework. My custom delegate message is not there. I am properly insulating the call:
if([delegate respondsToSelector:#selector(request:finishedWithResult:)])
[delegate request:self finishedWithResult:ret];
Aside from turning the warning off -- I like to work with as many warnings on as possible -- is there a way to communicate (either syntactically or via a compiler directive) that I am aware this message is undeclared? Should I, instead, be using an interface design pattern for this รก la Java? Using id<WillReceiveRequestMessages> or something?
Open to suggestion.
A better way of doing it would be to create your own delegate protocol:
#protocol MyControlDelegate <NSObject>
#optional
- (void)request:(MyControl *)request didFinishWithResult:(id)result;
#end
Then, you would declare your delegate like this:
id <MyControlDelegate> delegate;
The compiler will no longer complain when you write this:
if ([delegate respondsToSelector:#selector(request:didFinishWithResult:)])
[delegate request:self didFinishWithResult:result];
The <NSObject> syntax is important in the protocol definition because it tells the compiler to incorporate the NSObject protocol. This is how your protocol gets methods like respondsToSelector:. If you left that out, the compiler would start complaining about respondsToSelector: instead.
This is, presumably, because I'm declaring the delegate I'm calling
like this: ...and Xcode is checking what NSObject declares in the
Foundation framework.
That is incorrect. If that were the case then you would get a warning about the object "may not respond to" the method, or something like that. This is a completely separate problem.
This warning is due to the fact that the compiler must know the signature of a selector in order to call it. This is because, behind the scenes, the compiler translates a method call to either objc_msgSend or objc_msgSend_stret depending on whether the method returns a struct type or not. If it doesn't know the return type, it will guess that it is not a struct, and use the first function. However, this could be wrong.
The solution is to have the method declared anywhere at all. It doesn't even have to be declared in the right class. You can declare it in some dummy protocol that is never used. So long as it is declared somewhere, the compiler will know and will be able to correctly compile it.
I have a class with an delegate property. Anyone who wants to be a delegate must conform to a protocol. I defined everything like this:
#import <UIKit/UIKit.h>
#protocol TheDelegateProtocol;
#interface MyClass : UIView {
id<TheDelegateProtocol> theDelegate;
}
#property (nonatomic, assign) id<TheDelegateProtocol> theDelegate;
#end
#protocol TheDelegateProtocol<NSObject>
#required
- (void)fooBarWithFoo:(CGFloat)foo;
#end
Now the crazy thing is: I have another class that wants to be the delegate. So it conforms to that protocol, like this:
#import <Foundation/Foundation.h>
#class MyClass; // forward declaration. importet in implementation.
#protocol TheDelegateProtocol; // need forward declaration here, right?
#interface OtherClass : NSObject <TheDelegateProtocol> {
// ivars
}
#end
I can't get that to work. It says: "No definition of protocol 'TheDelegateProtocol' found". Well, that protocol is defined in MyClass, and I am importing MyClass in the implementation. Any idea what's wrong there?
Figured out something: In a method where I try to assign the protocol, it is telling me, that OtherClass does not conform to the protocol. But it does! That makes no sense. I also added the protocol method in the header....
Put the definition of the protocol in a separate file.
#import that file into any header file that needs it.
I think you need to #import the header file that defines the protocol. How can the compiler know which methods are available without it?
If you use another class (i.e., as an ivar or as a parameter to a method) then you can use a forward declaration. But if you subclass then you need to #import.
The compiler's warning is correct. OtherClass doesn't conform to the protocol because it doesn't declare the required fooBarWithFoo method that the protocol expects.
Have you tried it this way?
#import "MyClass.h"
#interface OtherClass : NSObject <TheDelegateProtocol> {
// ivars
}
- (void)fooBarWithFoo:(CGFloat)foo; // <<< missing bit
#end
He doesn't need to declare the methods to conform to the protocol. He only need to implement them in the .m file.
Is this a warning? because sometimes it does that when you have circular references and stuff, and it gets confused, but in reality its ok, have u tried running it to see if it works? In my project i have a bunch of warning about protocols not found, they are there though and it works fine... What you can do to get rid of the warning is try defining the protocol outside the class on some other .h file. You also dont really need the forward declaration, you can just do #import of the .h file its defined in
Your two classes differ in their use of the protocol.
MyClass does not implement the protocol, it has an attibute that is a pointer to a class that implements the protocol.
OtherClass should implement the protocol.
OtherClass needs to have available before its interface is defined all the details of the protocols, interfaces and classes that it inherits from. Thus you need the protocol in a header to be #imported in OtherClass.h
MyClass just needs to know the protocol exists in its interface.
Note on Stephen's reply subclassing is the case you can't use forward declarations of classes. (In the example OtherClass is a subclass of NSObject)
Also see Apple's Communicating with Objects, which discusses delegates, protocols, and selectors.