Multiple classes; same init selector with different argument types

Discussion in 'Mac Programming' started by Thomas Harte, Aug 5, 2010.

  1. Thomas Harte macrumors 6502

    Joined:
    Nov 30, 2005
    #1
    Apologies for the brief title. I have a whole bunch of classes that are more or less of the form:

    Code:
    @class ThisClass;
    
    @protocol ThisClassDelegate
    - (void)thisClassDidSomething:(ThisClass *)instance;
    - (void)thisClassDidSomethingElse:(ThisClass *)instance;
    /* etc */
    @optional
    /* some more things */
    @end
    
    @interface ThisClass
    {
    	/* whatever */
    	NSObject <ThisClassDelegate> *delegate;
    }
    
    - (id)initWithURL:(NSURL *)url delegate:(NSObject <ThisClassDelegate> *)delegate;
    Some of the delegate methods are optional; it is therefore necessary that the delegate be explicitly a subclass of NSObject rather than merely an id since respondsToSelector will be called on it.

    This is all fine, except that once I have more than one class which uses the selector initWithURL:delegate:, the following is prone to cause compiler and analyser warnings for one or the other:

    Code:
    SomeClass *class = [[SomeClass alloc] initWithURL:something delegate:this];
    The reason being that 'alloc' returns type id so the type isn't known for the purposes of checking the selector. So I get a warning that 'this' doesn't implement the correct protocol when the compiler checks with one of the various declarations of initWithURL:delegate: that requests an NSObject that implements a different protocol.

    It's slightly unwieldy, but I can fix that with:

    Code:
    SomeClass *class = [(SomeClass *)[SomeClass alloc] initWithURL:something delegate:this];
    And still get the warning I want to get if I've forgotten to implement the necessary protocol on the class that I'm nominating as a delegate. I guess I could also supply '+ (SomeClass *)alloc;' that called super alloc then casted the pointer and returned it.

    So, I know what causes the problem and I know some slightly displeasing ways to eliminate it. My real question is that, given that a lot of Objective-C is idioms and patterns, am I offending any of the normal conventions? I get a bit anxious any time that things don't end up being neat. Is someone with greater experience able to critique what I'm doing?
     
  2. lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #2
    I'm really not too well-versed with a lot of what you're working with, but I can offer one suggestion:
    Factory methods return a concrete type (or can). You could have:
    Code:
    +(SomeClass *)someClassWithUrl:andDelegate:
    I'm not 100% sure if this will help with your problem, but i thought i'd toss it out there.

    -Lee

    EDIT: Hrm. A quick review of the docs seems to indicate that, at least in Apple's classes, factory methods also return id. I don't know if this is an important convention to follow in your own code, but if so this advice is obviously no good.

    EDIT 2: It seems like the id return type for factory methods is for ease of subclassing, etc. If you have no intention to subclass SomeObject, a concrete return type is probably OK.
     
  3. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #3
    You could embed the class name in the method name, e.g.:
    initThisClassWithURL:delegate:

    You've already done precisely this with your delegate methods:
    - (void)thisClassDidSomething:(ThisClass *)instance;
    - (void)thisClassDidSomethingElse:(ThisClass *)instance;

    So do the same thing with your init methods.


    The red-hilited code is almost begging for a macro.
     

Share This Page