Back call

I am writing an iPhone application that in many places has to do non-HTTP or FTP networks of a very simple type of request response.

I wrapped it all up in a SimpleQuery class that integrates with the run loop.

SimpleQuery *lookup = [[SimpleQuery alloc] init];
[lookup setDelegate:self];
[lookup doQueryToHost:queryServer port:queryPort query:queryString ];   

      

As you can see, the caller sets itself up as a delegate. When the results are complete, it calls the delegate method with the results.

[delegate simpleQueryResult:resultString simpleQuery:self];             

      

Now I'm in a state where I have a SimpleQuery user that has two types of queries, so I need to extend SimpleQuery to support that.

I can think of two sane ways to do this.

First, pass the selector to doQueryString or a separate doQueryStringWithSelector.

[lookup doQueryToHost:queryServer port:queryPort query:queryString selector:@SEL ]; 

      

Second, by passing the tag to doQueryString so that when the delegate is called, it can request the tag when passed in to simpleQuery to see what the results are for.

[lookup doQueryToHost:queryServer port:queryPort query:queryString withTag:tag ];

      

I'm just wondering what is best in terms of coding style, the former seems to be simpler, but tagging is more like iPhone SDK and Interface Builder

+1


source to share


3 answers


The option, which is commonly used in Apple code (such as in UIControl), is intended to provide both a target and a selector. This only works if there is one callback and is more appropriate than a delegate in this case. (If there are multiple callbacks, then you probably have to go with a delegate and a tag.)

If you go this route, then you completely remove the delegate and instead use a method with this signature:

doQueryToHost:(id)queryServer port:(int)queryPort query:(NSString*)queryString target:(id)target action:(SEL)action

      



Note that "action" is usually preferred over "selector" in method arguments in this case. The request will simply call the target selector when done. This will allow your clients to have multiple selectors as well as multiple targets; this can help clean up the code because you don't need to embed everything in one delegate object.

If you want to go with your tag's route, you must name it the "context" that Apple uses (for example, in addObserver: forKeyPath: options: context).

+2


source


There is a third option, which has a common pattern in the sets, which is to use @protocol

s.

For example:

@protocol QueryCompleteHandlerProtocol
- (void)queryType1Complete:(int)intStuff;
- (void)queryType2Complete:(float)floatStuff;
@end

      

What this means is that it declares a set of method calls that the object accepting the protocol must match (the compiler will actually provide this).

Thus, your SimpleQuery object will contain something like a delegate pointer, which you can declare in this way among the ivars:

NSObject<QueryCompleteHandlerProtocol> *callback;

      

What this tells the compiler is that it callback

is an object that descends from NSObject

and accepts a protocol QueryCompleteHandlerProtocol

. Sometimes you see it like:

id<QueryCompleteHandlerProtocol> callback;

      



If you want to call the callback, there is nothing special, the methods SimpleQuery

will just call:

[callback queryType1Complete:1];
[callback queryType2Complete:2.0];

      

Finally, the client for the procotol class will declare itself as accepting the protocol:

@interface MyClass : NSObject<QueryCompleteHandlerProtocol>
...
@end

      

And will be used as a callback with some code like:

[lookup setCallback:self];

      

Here the compiler checks that it MyClass

matches QueryCompleteHandlerProtocol

, that is, it has implemented queryType1Complete:

and queryType2Complete:

.

+1


source


I'm not sure I understand the problem here. Can't the SimpleQuery user just set a different delegate object for the second request or branch in the simpleQuery: parameter? This is the main part of the delegate pattern, just like having two UIActionSheets for one view controller.

+1


source







All Articles