How to conform to a self-made protocol? - iphone

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.

Related

Declaring a delegate protocol

I would like to know what is the difference when declaring a protocol in the same class and when declaring it in a separate file; example :
#import <UIKit/UIKit.h>
#class MyClassA;
#protocol MyDelegate <NSObject>
#required
- (MyClassA*)myMythod;
#optional
- (void)anOtherMethod:(NSString*)ID;
#end
#interface MyClassB : UIViewController <UITableViewDataSource, UITableViewDelegate>
#property (nonatomic, assign) id <MyDelegate> delegate;
......
here I declare the protocol delagate in the same file with MyClassB, and I can declare it (the protocol delegate) in a separate source file. What is the difference between declaring it in the same file with the class and in a separate file? Thanks!
There definitely are subtle differences.
If the protocol you are talking about is a delegate that is used by one particular class, for example, MySpecialViewController, and MySpecialViewControllerDelegate, then you might very well like to keep the declaration of both of those in the same header. If another class is going to implement that protocol, for example, it's probably going to depend logically on the MySpecialViewController class. So, you're not introducing any additional dependencies.
But, there's another significant reason (at least) to use protocols. You might be trying to decouple a bidirectional dependency between two classes. Of course, the compiler doesn't let two headers #import one another. But, even if you move one class's #import to the .m file, it's often a sign of a poor design to have two classes each fully aware of one another's complete API.
One way to decouple this relationship a little is to make one class aware of the other only through a protocol that the other implements. Perhaps Parent owns and creates the Child class, and thus must #import "Child.h". But, the Child also needs to call the foo:bar: method on the Parent. You could make a FooProtocol:
#protocol FooProtocol
- (void) foo: (int) arg1 bar: (BOOL) arg2;
#end
And then in Parent.h:
#interface Parent : SomeBaseClass<FooProtocol> {
}
which allows Child to do this:
#interface Child {
}
#property (assign) id<FooProtocol> fooHandler;
and use it
[fooHandler foo: 1 bar: YES];
Which leaves the child with no direct dependency on the Parent class (or Parent.h). But, this only works if you keep the declaration of FooProtocol in FooProtocol.h, not in Parent.h. Again, if this FooProtocol was only ever used by Child, then it would make sense to keep it in Child.h, but probably not if this protocol was used by classes other than Child.
So, to summarize, keep your protocols in separate headers if you want to preserve the maximum ability to separate interdependencies between your classes, or to encourage better separation in your design.
No difference. It's just a matter of how you like to organize your headers.
For example, I like to keep everything related to "one functional entity" (whatever that means, the definition varies :-)) in one file. A class that is using delegates that implement a protocol would therefore declare the class and the protocol in the same header, since they are pretty much just different bricks of the same building.
The only difference between having your protocol in a separate header file to your class's header file is it allows for including the protocol to be optional, this could aid in resolving any naming clashes, but prefixing your protocols should be the solution for that.
The convention seems to be to include relevant protocols inside the class's header file, as that way it's more organized and kept together, but if you have extremely large protocols it may make more sense to have them in separate files in order to make your class headers easier to read.

Headers #import versus #class [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
#class vs. #import
In the .h file you can add a class to be seen(dont know what the correct terminolgy for this is) by using
#import "SomeClass.h"
or instead use
#class SomeClass;
I've tried both methods and they both worked. Whats the difference? Should I be using one of the methods and not the other? What is best practice?
#import includes the content of the header in the source.
Thus, every declaration which is in the imported header is also imported.
#class only declares to the compiler that the given class exists, but does not import the header itself. It is called a forward declaration, as you only declares to the compiler that the class exists before defining it in details (telling which methods it implements and so on)
Consequences:
When using #import in your .m file, if the header is modified, it will trigger the recompilation of the .m file that #import it on next compilation. Instead, if you use #class, your .m does not depend on the header and if the header is modified, the .m file is not recompiled.
Using #class also avoid cross-imports, e.g. if the class A references class B and class B references class A, then you can't #import "A.h" in B.h and #import B.h in A.h in the same time (it would be an "import infinite loop")
Using #class only declare that a class exists and does not tell the compiler which methods the class responds to.
This is why usually the best practice is to forward-declare the class using #class A in the header (.h) files that references class A, just so that the compiler knows that "A" is a known class but doesn't need to know more, and #import "A.h" in the implementation (.m) file so that you can call methods on the objet of class A in your source file.
In addition to avoid import loops, this will also avoid to recompile files if they don't need to, and thus reduce your compile time.
The only exceptions are when the declaration of your class inherits another class, or when it declares that it conforms to a given #protocol (like delegate protocols and so on), because in this particular case, the compiler needs you to #import the whole definition of the parent class or #protocol (to know if your class correctly conforms to this given protocol).
MyClassA.h
// Tells the compiler that "MyClassB" is a class, that we will define later
#class MyClassB; // no need to #import the whole class, we don't need to know the whole definition at this stage
#interface MyClassA : NSObject {
MyClassB* someB; // ok, the compiler knows that MyClassB is a class, that's all it needs to know so far
}
-(void)sayHello;
-(void)makeBTalk;
#end
MyClassB.h
#class MyClassA; // forward declaration here too
// anyway we couldn't #import "MyClassA.h" here AND #import "MyClassB.h" in MyClassA.h as it would create an unsolvable import loop for the compiler
#interface MyClassB : NSObject {
MyClassA* someA; // ok, the compiler knows that MyClassA is a class, that's all it needs to know so far
}
-(void)talk;
-(void)makeABePolite;
#end
MyClassA.m
// import MyClassB so that we know the whole definition of MyClassB, including the methods it declares
#import "MyClassB.h" // thus we here know the "-talk" method of MyClassB and we are able to call it
#implementation MyClassA
-(void)sayHello { NSLog(#"A says Hello"); }
-(void)makeBTalk {
[someB talk];
// we can call the 'talk' method because we #imported the MyClassB header and knows this method exists
}
#end
MyClassB.m
// import MyClassA so that we know the methods it declares and can call them
#import "MyClassA.h"
#implementation MyClassB
-(void)talk { NSLog(#"B is talking"); }
-(void)makeABePolite {
[someA sayHello];
// we can call this because we #import MyClassA
}
#end
PS: Note that if this is a best practice, I know a lot of developers (including myself sometimes ^^) that #import the header it needs in their .h files, instead of only forward-declare it using #class... this is some bad habit — or because these developers doesn't know these subtleties — that you will unfortunately encounter in existing code anyway.
Using #class is called forward declaration. Since usually you don't need to know the specifics of the class in the .h file, this is usually all you need.
Forward declaration prevents you getting into a situation where you import a particular .h file, which says to import another .h file, which says to import the original .h file again, and so on.
The #class forward declaration allows you to have your interfaces behave like interfaces. Meaning: Declare your code.
But this doesn't mean that you can leave out the #import statement. You just moved the responsibility to the implementation to import and make use of it.
Basically it could be seen as an increase in performance as you're not importing any other headers inside your current header.
Important Note: This isn't the case when you're working with delegates.
If you're making use of delegates you always have to have the proper #import statements in place so that the compiler knows which delegate methods are to be implemented by that class.
You might also want to have a look at the following SO question: #class vs. #import

NSObject why is alloc declared in both NSObject and NSProxy yet retain is in the NSObject protocol

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.

Objective-C when to declare what methods in #interface

When and what methods should be declared in the #interface section of a class? As I understand, methods that describe what your class does should be declared in the #interface section, but other "helper" methods should not be declared. Is this a correct understanding from my side?
One way is to declare the instance methods in .h file. And, declare the private methods inside the .m, using a Category.
For example, in MyOwnClass.h file.
#interface MyOwnClass
- (void)aInstanceMethod;
#end
And, inside your MyOwnClass.m file, before the #implementation block,
#interface MyOwnClass (MyPrivateMethods)
- (void)aPrivateMethod;
#end
You usually should add your methods to the .h file when you want an external class to have access to it (public methods).
When they're private (only used internally by the class) just put them in your .m file.
Anyway, it's just a pattern. As Objective-C works with messages, even if you don't set a method in your .h file an external file can access it, but at least your auto-complete won't show it.
You should declare all your methods in your .h
The tip from EmptyStack is nice but it's just a tip.
If you don't intend to ship your binary as an SDK, you don't really need it.
Objective-C doesn't have (yet) private methods.

iphone - performSelector:withObject:afterDelay:' not found in protocol(s)?

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