Protocols in iPhone SDK - iphone

I am confused about the #protocol----#end in iphone, what actually is it meant for. Why we are using this. Is it a functionality to provide additional methods to a class..? i am not sure.
Please help me.
Thanks,
Shibin

protocol is used to declare a functionality which is going to used by many objects or classes.
Consider an example, You are developing a birds database. So you will be having the bird as a Base class and you will inherit the bird to create your own bird. so in bird class you will not be having any definitions but some behaviors which all birds will have to inherit. Like birds can fly, has wings like that. So what will you d is you will declare all those behaviors and implement them in your derived classes. Because there may be birds which cal fly high and for long distance and some will fly short distances.
For serving this purpose #protocol is used. Using #protocol you declare some behaviors. And use those behaviors in your other classes for implementing the behavior.
This will avoid the overhead of declaring same method again and again and makes sure that you implement the behavior in your class.

#protocol is equivalent to an interface in Java.
#protocol Printable // Printable interface
- (void) print;
#end
#interface MyClass: NSObject <Printable> { ... }
// MyClass extends NSObject implements Printable

#protocol can be used to define a delegate.
For example:
#protocol SomeDelegate
- (void)delegateActionCompleted;
#end
#interface MyClass: NSObject {
id<SomeDelegate> _delegate;
}
#end
And then the implementation (.m) file:
#implementation MyClass
- (void)performAction {
// do the actual work
if (self._delegate && [self._delegate respondsToSelector:#selector(delegateActionCompleted)]) {
[self._delegate delegateACtionCompleted];
}
}
#end

It should be better to use something like
if (self.delegate && [self.delegate conformsToProtocol:#protocol(YourProtocolName)]) {
...
}
to check whether the delegate is actually conforming to a specified protocol.

Related

Two Interfaces?

DataController.h
#class Play;
#interface DataController : NSObject
- (unsigned)countOfList;
- (Play *)objectInListAtIndex:(unsigned)theIndex;
#end
DataController.m
#import "DataController.h"
#import "Play.h"
#interface DataController ()
#property (nonatomic, copy, readwrite) NSMutableArray *list;
- (void)createDemoData;
#end
#implementation DataController
#synthesize list;
- (id)init {
if (self = [super init]) {
[self createDemoData];
}
return self;
}
Why do you think that #interface is defined twice? And also whats the meaning of ()? Shouldn't there be a class name maybe the super class between the parentheses?
In general, the syntax #interface ClassName (CategoryName) is for declaring a category. Categories are a way to add methods to a class. You can do this even with classes for which you don't have the source code. See more here.
#interface ClassName () (with nothing in the parentheses) is essentially a special case of a category and is called a class extension. The primary difference between a class extension and a category is that methods declared in a class extension must be defined/implemented in the main #implementation block for the class, or you'll get a compiler warning. Methods in a regular category can be defined in an external #implementation block.
The most common use for class extensions (as in this case) is for declaring private methods. Objective-C doesn't have support for true private methods, so an easy way to accomplish the same basic end result is to declare private methods in a class extension at the top of the .m file. Since these methods aren't defined in the .h file, other classes won't see them, and you'll get a compiler warning if you try to use them outside the class they belong to.
You can also redeclare a readonly #property as readwrite in a class extension. That way, code external to the class implementation can only read a property's value, but inside the class's implementation, you can write to it too. This is the only case where it's allowable to redeclare an #property.
(Note that class extensions were a new feature in Objective-C 2.0 and aren't available on Mac OS X 10.4 and earlier.)

Adding category method to NSObject, but getting warnings because it's not in the <NSObject> protocol when I call it

(I found some questions discussing the idea, but I didn't see a solution for my problem.)
I added this convenience method as a category to NSObject. (I've added other methods, so I'm still interested in an answer even if you disagree with this particular convenience method.)
#implementation NSObject (MyCategory)
- (void)performInvocationOnMainThread:(NSInvocation *)invocation waitUntilDone:(BOOL)waitForMainThread;
#end
Then I have a protocol I defined:
#protocol MyDelegateProtocol <NSObject>
- (void)myDelegateProtocolMethod;
#end
Then I declare the delegate as a property of my class that implements said protocol.
#property (nonatomic, assign) id <MyDelegateProtocol> delegate;
But when I try to call the NSObject method I added in my category like so
NSInvocation *invocation = [self.delegate invocationForSelector:#selector(someSelector:withArg:)];
I get this warning
'-performInvocationOnMainThread:waitUntilDone:' not found in protocol(s)
If I cast my delegate as (NSObject *) then I don't get the warning. What am I doing wrong? It didn't seem like I could (or should?) add methods to an existing protocol without creating a "sub protocol" and using it from then on. (Which kind of defeats the point of adding methods to NSObject in mind.)
NSInvocation *invocation = [(NSObject *)self.delegate invocationForSelector:#selector(someSelector:withArg:)];
Your category extends the NSObject class, not the NSObject protocol. While the class now has the method, it's not defined as part of the protocol, hence the warning.
That's why typecasting to the NSObject * pointer type works; you're casting to the NSObject class type, rather than something like id<NSObject> which means an arbitrary Objective-C object that conforms to the NSObject protocol.
You'll have to make an intermediate protocol (or "sub protocol") that extends the NSObject protocol:
#protocol ExtendedNSObject <NSObject>
- (void)performInvocationOnMainThread:(NSInvocation *)invocation waitUntilDone:(BOOL)waitForMainThread;
#end
Then have your delegate protocol extend that one instead:
#protocol MyDelegateProtocol <ExtendedNSObject>
- (void)myDelegateProtocolMethod;
#end
If I'm not wrong, you can keep the existing NSObject (MyCategory) implementation, and they'll play nice together.
when pass/expect this type, qualify it like so:
- (void)race:(NSObject<MyDelegateProtocol>*)arg;

cocoa - referencing a method on the parent

I had a method on my main view controller named "calculateThis".
This method was run, obviously, as
int newValue = [self calculateThis:myVariable];
when I run it from inside the view controller.
Then I created a static class and I need to run this method from there.
How do I reference this method from that class using just relative references, as super, superview, delegate, etc. I cannot use the class name defined on the delegate because this static class is used in several apps of mine.
I need to go up in the hierarchy, I imagine one level, and access the method there...
thanks.
Define your utility methods in a category on NSObject or related subclasses of NSObject.
Which you have done.
Adding (id)sender to your method will work. Then your method can reference the object that called it. Something like this.
+(int)calculateThis:(id)sender userInfo:(id)info;
then your call becomes.
int newValue = [NSObject calculateThis:self userInfo:myVariable];
If your intent is to create a class that you can use without initializing it, that's possible using class methods. For instance, if I want to make a class called MyClass with a doSomethingWith: method, I would define the following:
In MyClass.h:
#interface MyClass : NSObject {
}
+(void)doSomethingWith:(id)thisObject;
#end
In MyClass.m:
#import "MyClass.h"
#implementation MyClass
+(void)doSomethingWith:(id)thisObject
{
// Your code goes here.
}
#end
To reference this method in another class, you can use the class object for MyClass like so:
[MyClass doSomethingWith:#"Hello, World!"];
This isn't really a typical Cocoa or Cocoa Touch design pattern, but can be handy for things like calculations.
Are you talking about the superclass? If so, you use [super ...].

Objective C: Class Extensions and Protocol Conformation Warnings

I have a large class, which I have divided into several different class extension files for readability.
#protocol MyProtocol
#required
-(void)required;
#end
#interface MyClass : NSObject <MyProtocol>
#end
#interface MyClass (RequiredExtension)
-(void)required;
#end
Is there a better way to do this, without the compiler warning?
warning: class 'MyClass' does not fully implement the 'MyProtocol' protocol
Use a category for each protocol implementation. I use this when I have complex viewControllers.
For example, I have a category that implements NSTextDelegate protocol.
So, MyComplexViewController+NSTextDelegate.h:
#import "MyComplexViewController.h"
#interface MyComplexViewController (NSTextDelegate) <NSTextDelegate>
#end
and MyComplexViewController+NSTextDelegate.m:
#import "MyComplexViewController+NSTextDelegate.h"
#implementation MyComplexViewController (NSTextDelegate)
- (BOOL)textShouldBeginEditing:(NSText *)textObject{
...
}
- (BOOL)textShouldEndEditing:(NSText *)textObject{
...
}
- (void)textDidBeginEditing:(NSNotification *)notification{
...
}
- (void)textDidEndEditing:(NSNotification *)notification{
...
}
- (void)textDidChange:(NSNotification *)notification{
....
}
#end
Then I take all the headers for the main class definition and the categories and combine them into one header which I then import where I need to use the class.
#interface MyClass : NSObject
#end
#interface MyClass (RequiredExtension) <MyProtocol>
-(void)required;
#end
Adopt the protocol in the category.
You don't need to change your style of coding. To get around the warning, it only need to implement "required" method of the protocol, not "optional"
If that's only for readability, you should use categories only. A protocol is not needed in such a case.

How can one inherit two classes at same layer?

I am new at the area of iPhone. i am trying to build an iPhone app by using Cocos2d. I have used this type of classe like bellow-
#interface MenuScene : Scene {}
#end
#interface FlipView : UIImageView
{
CGPoint startTouchPosition;
NSString *dirString;
UIImageView *firstPieceView;
UIImageView *secondPieceView;
}
#end
#interface HelloController : UIViewController
#end
#interface MenuLayer: Layer{
Menu * menu;
NSString *dirString;
CGPoint startTouchPosition;
}
-(void) button1: (id)sender;
-(void) button2: (id)sender;
-(void) black_jack: (id)sender;
#end
and i want to inherit two classes(FlipView, HelloController ) to MenuLayerClass. but how can i do it. Actually what will be syntax. Pls reply any comment with code or syntax how i can do it.
You can't. As Clark says, Objective-C does not support multiple inherritance. This is because the designers believe that the advantages of multiple inherritance do not justify the complexity and bad design it encourages.
Instead, they have included something that will meet your needs. You can declare a 'protocol' using the #protocol directive. A protocol describes a set of methods a class responds to but cannot add data to an object.
To use a protocol, you include the protocol name in angle brackets after the super class.
e.g.
#protocol myProtocol
-(void)myProtocolMethod
#end
#interface myClass : NSObject <myProtocol>
{
int someData;
}
Will give an NSObject subclass that must also respond to (void)myProtocolMethod messages.
That said, I would agree with Clark that you should review your design - having a single object that is both FlipView, HelloController does not sound good. You should probably implement a FlipController and use a third class (the model) to synchronise state between the two controllers - or if your app is very simple, have a single class that acts as a delegate for both FlipView and UIController.
You cannot, as Objective-C does not have multiple inheritance. Additionally, it doesn't really make sense to have a single class be both a view and a view controller.