Objective-c (iphone) best practice service data dispatching
I'm struggling with how i'm going to design my service fetching pattern
i've come up with this so far:
ServiceCaller ( this will be the only class that the client will use it has all the methods that are for accessing a certain part of the webservice, like requestHello, requestLogon, requestUserDetails, ...)
ServiceConnector ( this class is instantiated in the service caller, this class will do the actual connection to the server request the data and return it back to the caller who needs to dispatch it back to the client, in the service conn开发者_Python百科ector i use a a abstract factory pattern to separate the request logic and determine which part of the webservices needs to be called en parsed )
the problem i'm facing with is how will i handle my dispatching back to the client. i was thinking about making the servicecaller a singleton so it has only 1 instance of the servicecaller and therefor 1 instance of the service connector but leaving it open to have multiple connections to the server at the sametime. and handle the callbacks with a delegate property
but when for instance 2 calls are done in 2 separate views i change the delegate property which means only the call that would be done last receives his callback , the other one doesn't.
Anyone have an idea how i could fix this problem?
One approach is to drop the delegate pattern for another call back pattern: continuation style. The idea is for your API to take a continuation block as a parameter. When it's done doing its job, it simply call the continuation block. Here is an example of an API procedure:
typedef void(^ContinuationBlock)(id result, NSError *error);
- (void) answerTheDefinitiveQuestion:(Towel *)h2g2Towel do:(ContinuationBlock*) continuation
{
if (h2g2Towel) {
double answer = 7 / h2g2Towel.length * (sqrt(h2g2Towel.area+2*h2g2Towel.area+1) - 1) * 6 / h2g2Towel.width;
continuation([NSNumber numberWithDouble:answer], nil);
} else {
NSError *err = [[[NSError alloc] initWithDomain:H2G2Domain code:kMissingTowel userInfo:nil] autorelease];
continuation(nil, err);
}
}
Now the client can use it that way:
- (void) doSomething
{
[myServiceCaller answerTheDefinitiveQuestion:self.towel do:^(NSNumber * answer, NSError *error) {
if (!answer) {
NSLog("No answer available because %@, %@", error, error.userInfo);
} else {
NSLog("haha, Zaphod, your answer is %@, %@", answer);
}
}];
}
Note: this example is synchronous, but it works just fine in an asynchronous context. You can bracket the implementation of answerTheDefinitiveQuestion:do:
in a call to dispatch_async
for example.
Indeed, this approach is very well suited to an all-asynchronous API. The only thing to remember is that if you store the continuation block to be called later, you must store a copy, because the block as you get it is stack-based and will disappear when your function returns. Simply do:
self.myClientContinuation = [continuation copy];
PS: the whole singleton idea is evil. At least in your design, there doesn't seem to be any point for ServiceCaller to be a singleton (as opposed to ServiceConnector).
精彩评论