Ehtesham Hasan Ehtesham Hasan - 3 months ago 7
Objective-C Question

Storing a parameter value to be returned later in delegate callback

I have a singleton class and a protocol defined as below. (Simplified)

@protocol ClassADelegate <NSObject>

- (void) classADelegateDidFinishSomething:(BOOL) aBool;

@end


@interface ClassA : NSObject

@property (nonatomic, weak) id<ClassADelegate> delegate;

+ (ClassA *) shared;
- (void) methodA:(BOOL) aBool;

@end


The
methodA
method causes a chain of asynchronous callbacks internally and finally in a private method needs to call the delegate method like the following way.

if (self.delegate)
{
[self.delegate classADelegateDidFinishSomething:BOOL_FROM_methodA];
}


Now
BOOL_FROM_methodA
in the above method must be the same as the
aBool
in the
methodA
method. So I have to store the value of the
aBool
somewhere. Lets say I store it in a private variable
_aBool
like the following and later using this to call the delegate method.

- (void) classMethodA:(BOOL) aBool
{
_aBool = aBool;
...
}

- (void) aPrivateMethod
{
....

if (self.delegate)
{
[self.delegate classADelegateDidFinishSomething:_aBool];
}
}


This solves the problem if it was guaranteed that no further calls to
classMethodA
is done before the delegate method is called. But imagine the following situation.

[[ClassA shared] methodA:YES];
[[ClassA shared] methodA:NO];


For the above code, both of the
classADelegateDidFinishSomething
callbacks will have
NO
as their parameter value, even though the 1st
methodA
call has
YES
as its parameter.

I would like to get an elegant solution to the problem without refactoring most of my code.

Answer

You're implementing something that requires context (multiple requests) using structures that are inherently one-to-one (singleton, delegate). This isn't a good match.

Options that come to mind are to use a unique instance of ClassA for each invocation of methodA or to rewrite ClassA methods so that the caller supplies its own context.

For example:

- (void)classMethodA:(BOOL)aBool listener:(id<ClassADelegate>)listener;

That way, you could map each call to the object that made it.


Or, if there's only one delegate making multiple calls, replace the listener object with any kind of context parameter that can be used to tag the calls.

- (void)classMethodA:(BOOL)aBool context:(id)context;
- (void)aPrivateMethod:(id)context;

For either of those options, your singleton can maintain a collection that maps calls to responses.

Comments