Search code examples
objective-cselectorobjective-c-blocksclass-method

setting a protocol's base class property to a method using a selector or a block


I am creating an interface/protocol that will be used for iOS grid views. Im trying to encapsulate as much information within the class, leaving very little info to the user of the class and its subclasses. I'm stuck at what a callback method or a delegate should be. In C or C++ I would have required a function pointer to be passed as a parameter for the method that would be called on a touch up event. In Objective C (which Im fairly new at), I'm puzzled with blocks and selectors. From what I've seen the Apple way is to use selectors. So This class should require a method to be set as a selector for what will happen when a touch up event is detected. I do not want to do extensive subclassing, as this will limit reusability and enforce more coding to take place every time this interface is used. I am including limited code, of what I've done so far, using a selector, but I am open to suggestions on how the same could be done with a block instead and why it would be better. I have not tested this, I am currently designing it.

@protocol Grid <NSObject>
@required

/*! @brief Initializer for base class */
- (id) init:(UIView *)parent withSelector:(SEL)selector;
/*! @brief Draw the actual view */
- (void) draw:(CGRect) rect;
/*! @brief Reload the data */
- (void) reload;
@end

The title is misleading, and I have, since posting this question, got a better idea of how things work in Objective-C. This is about abstracting base classes, inheritance and polymorphism, rather than setting selectors as properties or delegates


Solution

  • what you should do is require that the class (presumably a delegate) conforms to your protocol. You can do that like this.

    @interface GridView : UIView {
        id<Grid> delegate;
    }
    
    ...
    
    @end
    

    and have the user specify the delegate property. At this point, all you know about the delegate, is that it conforms to the Grid protocol, so you can be sure that it implements all of its required methods. Note that you should never have any sort of init method in a protocol, because your class (GridView) should never have to allocate its own delegate, that defeats the purpose entirely.

    In the class that you're going to use as a delegate, you have to make sure that it conforms to the Grid protocol so that it can be used as a delegate. That would look like this.

    @interface GridDelegateObject : NSObject <Grid> {
    ...
    }
    
    ...
    
    @end
    

    and you would have to provide an implementation for at least the required methods in the Grid protocol.

    then you should set the delegate of the GridView instance to an instance of GridDelegateObject.

    [gridViewInstance setDelegate:gridDelegateObjectInstance];

    then you can call all of the methods that gridDelegateObject implemented from your Grid protocol from gridViewInstance, like this.

    -(void)someMethod {
        [delegate reload];
    }
    

    or something like that. Which will call the reload function on gridDelegateObjectInstance.