[Sample Code] Simple protocols.

Discussion in 'iOS Development' started by SkylarEC, Jul 14, 2009.

  1. SkylarEC

    SkylarEC Super Moderator Emeritus Staff Member

    Joined:
    Sep 19, 2007
    Messages:
    6,642
    Likes Received:
    129
    A topic that is certain to come up eventually is how to implement your own protocols. Such as UITableView's datasource and cellForRow: and UIResponder's touchesBegan: methods.

    Possibly you create a certain new type type of button object, a worker object that reports when it is done, or any other possibility your wicked little minds can create. The reasons for delegation are virtually endless.

    In the sample provided, I take a custom view of mine called PTGlossyView, which I subclassed into my PTStatusBar. You will be able to see this object ad code in action with the release of PocektTouch 4.0 (available in the AppStore soon). I want touches on the PTStatusBar to react differently than the touches in the main view part of the application. In other words, I want swipes and touches in the application's status bar to not be passed on to its super, and to perform its own touch methods.

    Now, the simplest method would be to override the PTStatusBar's touch methods and simply perform whatever code needs to be performed. The problem with this solution is that I also have a touch engine that handles touch events and has several supporter methods. I would end up having to duplicate most of the touch engine within this view, nearly doubling my touch handling code. Alternatively, I could include my touch engine as an object within the PTStatusBar. That presents the problem of memory usage, as I would have an extra touch controller, which would have to create a music controller to manage (which the original touch engine knows nothing of).

    The simplest way to handle situations like these is to create a new protocol and delegate the PTStatusBar's actions to another objects. That is, have the view controller that contains the PTStatusBar assign the touch engine as the delegate of the PTStatusBar. Then, I'd implement the status bar's touch methods within the already existing touch engine, which would include access to its supporter methods, and the whole world is happy.



    To do this, the first thing I do is prepare my PTStatusBar for delegation.
    [OBJC]//
    // PTStatusBar.h
    // PocketTouch
    //
    // Created by Skylar Cantu on 7/14/09.
    // Copyright 2009 Skylar Cantu. All rights reserved.
    //

    #import <Foundation/Foundation.h>
    #import "PocketTouch.h"

    @protocol PTStatusBarDelegate;

    @interface PTStatusBar : PTGlossyView {
    id<PTStatusBarDelegate> delegate;
    }

    @property (nonatomic, assign) id<PTStatusBarDelegate> delegate;

    @end

    @protocol PTStatusBarDelegate <NSObject>
    @optional
    - (void)statusBarTouchesBegan

    Please Register or Log in to view images

    NSSet *)touches withEvent

    Please Register or Log in to view images

    UIEvent *)event;
    - (void)statusBarTouchesMoved

    Please Register or Log in to view images

    NSSet *)touches withEvent

    Please Register or Log in to view images

    UIEvent *)event;
    - (void)statusBarTouchesEnded

    Please Register or Log in to view images

    NSSet *)touches withEvent

    Please Register or Log in to view images

    UIEvent *)event;
    - (void)statusBarTouchesCancelled

    Please Register or Log in to view images

    NSSet *)touches withEvent

    Please Register or Log in to view images

    UIEvent *)event;
    @end
    [/OBJC]

    As you can see, you create the interface of the object exactly the same way as you would create any other object interface. Notice the id<PTStatusBarDelegate> delegate; We set that up as an Ivar that accepts any object that conforms to the PTStatusBarDelegate protocol. It's that easy. In our property declaration, we create a property that assigns our object its delegate.

    The only thing of note is that after the interface we also define a protocol, called the PTStatusBarDelegate. NOTE, this doesn't have to be here, it can be in an other header. I like to keep protocol definitions with the actual object, for ease of reference, but the choice is yours where you define it.

    Since a protocol isn't an interface, we replace the @interface with @protocol on its declaration. We also need to state that it conforms to the NSObject protocol by adding the <NSObject>. Very simple enough, and so far is a lot like the interface declarations you're used to.

    The next keyword that you see is @optional. This tells the compiler that the following methods are optional, and that it shouldn't throw warnings and errors if it methods are not implemented by the actual delegate. The counterpoint to @optional would be @required, which tells the compiler that the delegate MUST implement the following methods. By default, methods are @required.

    Now, we @end out protocol definition just like any other object's declaration. And we begin the interface of our object.
    [OBJC]//
    // PTStatusBar.m
    // PocketTouch
    //
    // Created by Skylar Cantu on 7/14/09.
    // Copyright 2009 Skylar Cantu. All rights reserved.
    //

    #import "PTStatusBar.h"


    @implementation PTStatusBar

    @synthesize delegate;

    - (void)touchesBegan

    Please Register or Log in to view images

    NSSet *)touches withEvent

    Please Register or Log in to view images

    UIEvent *)event {
    if (self.delegate != nil && [self.delegate respondsToSelector

    Please Register or Log in to view images

    selector(statusBarTouchesBegan:withEvent

    Please Register or Log in to view images

    ])
    [self.delegate statusBarTouchesBegan:touches withEvent:event];
    }

    -(void)touchesMoved

    Please Register or Log in to view images

    NSSet *)touches withEvent

    Please Register or Log in to view images

    UIEvent *)event {
    if (self.delegate != nil && [self.delegate respondsToSelector

    Please Register or Log in to view images

    selector(statusBarTouchesMoved:withEvent

    Please Register or Log in to view images

    ])
    [self.delegate statusBarTouchesMoved:touches withEvent:event];
    }

    - (void)touchesEnded

    Please Register or Log in to view images

    NSSet *)touches withEvent

    Please Register or Log in to view images

    UIEvent *)event {
    if (self.delegate != nil && [self.delegate respondsToSelector

    Please Register or Log in to view images

    selector(statusBarTouchesEnded:withEvent

    Please Register or Log in to view images

    ])
    [self.delegate statusBarTouchesEnded:touches withEvent:event];
    }


    - (void)touchesCancelled

    Please Register or Log in to view images

    NSSet *)touches withEvent

    Please Register or Log in to view images

    UIEvent *)event {
    if (self.delegate != nil && [self.delegate respondsToSelector

    Please Register or Log in to view images

    selector(statusBarTouchesCancelled:withEvent

    Please Register or Log in to view images

    ])
    [self.delegate statusBarTouchesCancelled:touches withEvent:event];
    }

    @end
    [/OBJC]


    As you can see, this is just as easy as a standard object implementation. Since I am dealing with touch events, I override the PTStatusBar's touch methods. I do not pass the touch events onto to super because I want the responder chain to stop here. I then check to see if the delegate has been assigned (is not nil) and that it responds to the delegate methods. If both of these conditions are met, then we tell the delegate to perform the delegate methods.

    Now, I should note that I used touch events. You can call a delegate method from anywhere you'd like. Possibly in some method that executes a lot of code, you could have [self.delegate didSucceedItsComplexTask:aBool withResults:someData]; The point is to use these methods wherever they are most appropriate.

    Oh, by the way, this implementation is done. Of course, yours may have much more code, but that is entirely dependent on you and what you are having your object's code. The next step is to actually implement this in your app itself.

    In which ever object will become your object's delegate, we need to alter the interface declaration just a smidge (as we already do with UINavigationControllers, UITableViews, and UIScrollviews, for example). Take the declaration line and add <PTStatusBarDelegate> to it.
    [OBJC]@interface SomeObject : NSObject <PTStatusBarDelegate> {[/OBJC]

    Now, in the object that contains the PTStatusBar and your delegate object (possibly the view controller itself), simply do something like this:
    [OBJC]PTStatusBar *statusBar = [init... ];
    statusBar.delegate = someObject; //Or self, or whatever[/OBJC]
    If you are doing this in Interface Builder, then click on your view on the build view and use Inspector to view its properties. You'll see 'delegate.' Click on the circle and drag that to the object that will be its delegate: either some object, or the File's Owner (if you want the view controller to be the methods, this is equivalent to object.delegate = self

    Please Register or Log in to view images

    .

    You are now done setting everything up. You don't have to do anything else, and your application will work fine. But as of right now, we are not implementing the delegate methods. Let's go ahead and add those into whichever object will perform them.
    [OBJC]#pragma mark
    #pragma mark PTStatusBarDelegate Methods

    - (void)statusBarTouchesBegan

    Please Register or Log in to view images

    NSSet *)touches withEvent

    Please Register or Log in to view images

    UIEvent *)event {
    NSLog(@"Touch Down");
    }

    - (void)statusBarTouchesMoved

    Please Register or Log in to view images

    NSSet *)touches withEvent

    Please Register or Log in to view images

    UIEvent *)event {
    NSLog(@"Touch Moved");
    }

    - (void)statusBarTouchesEnded

    Please Register or Log in to view images

    NSSet *)touches withEvent

    Please Register or Log in to view images

    UIEvent *)event {
    NSLog(@"Touch Up");
    }

    - (void)statusBarTouchesCancelled

    Please Register or Log in to view images

    NSSet *)touches withEvent

    Please Register or Log in to view images

    UIEvent *)event {
    NSLog(@"Touch Cancelled or \"Out Of Bounds\"");
    }[/OBJC]


    As you see, this is exactly the same as any other method in your application. Congratulations, you have now successfully designed and implemented your custom protocol. Feel free to add some code to do some neat things. Your imagination is your limit.

Share This Page