I did quite a bit of research on this, but I am having a mental block about my problem. I am working on Objective-C for an iOS app
Here's my set up:
The view controller gets a text from the view (user input), and passes that text to the MethodA of the model.
The MethodA in model works on the input text and gets an output (e.g. searches google for that text). It does the search using dispatch_async method which calls the selector to MethodB within model.
MethodB parses the output and puts all the results into a NSMutableArray
My Question Here: how do I pass that NSMutableArray back to view controller so I can show it on the view?
Sorry, if the answer to my question is very simple/obvious. I am new to Objective-C
I guess passing along a delegate-object that respoons to a selector-method and calling this method with the processed data will be a good way to achieve the loosley coupled structure your program deserves. Are you familiar with this concept, or shall I dig up some code-samples for you?
UPDATE: Code samples
So, I would probably use the calling class, say MyViewController
, to implement the callbackMethod, myCallbackMethod
as follows:
-(void) myCallbakcMethod: NSMutableArray* array {
//DoWhatever with the returned data
}
The point is to get the result passed back to this method when the computation is finished.
So in your MyViewController
where you call MethodA
you pass along a reference to the delegate to handle the result, namly self
.
//From this:
[MyModel methodA:param1]
//To:
[MyModel methodA:param1:self]
MyModel
s methodA
and methodB
would need to add a parameter (id)delegate
and pass that along between the calls.
In methodB
where the data myArray
is ready, do the following call:
if([delegate respondsToSelector:@selector(myCallbackMethod:)]])
[observer performSelector:@selector(myCallbackMethod:) withObject:myArray];
Any time I want to do async processing and that stuff needs to get back into the UI somewhere, I do one of two things:
1. Use NSNotification to tell anyone who cares that the work is complete
2. Use a delegate property on the worker and a @protocol
1 NSNotification
The model object should document in it's .h file that it fires notifications when certain things happen; such as when a portion of the model has been updated. When the ViewController initializes the model object, have it set itself up as an observer of the documented notification, and implement a callback which updates the UI.
2 delegation and @protocol
Create a @protocol such as @protocol FooModelUpdateDelegate
with a method properly named such as fooObjectDidUpdate:(Foo *)object;
, and then the model class has a delegate property as id<FooModelUpdateDelegate> updateDelegate
and the ViewController sets itself as that delegate, and I'm sure you can figure out the rest.
In your view controller:
// your controller code
...
[myModel getSearchResult:searchKeyword receiver:self action:@selector(responseReceived:)];
}
- (void)responseReceived:(MyModel *)model
{
NSArray *searchResult = model.searchResult;
[model release], model = nil;
// some view actions, for instance update your table view
...
}
In your model:
...
- (id)getSearchResult:(NSString *)searchKeyword receiver:(id)aReceiver action:(SEL)receiverAction {
self.receiver = aReceiver;
self.action = receiverAction;
// some async actions
}
In async response receiver:
...
[self.receiver performSelector:self.action withObject:self];
}
Unless I'm misunderstanding your description it sounds like your "model" class is doing more than it should. In this case it's doing at least some of the work of your controller. My suggestion would be to fold methodA and methodB into the view controller (or another controller class). Method B could still set the NSMutableArray property of "model" instance, if that's essential (or skip that step if it's not).
-(void)methodA {
NSMutableArray *someArray = ...
[self methodB:someArray];
}
-(void)methodB:(NSMutableArray*)array {
NSLog(@"%@", array);
// do something with the array, like update the view
}
But if both are methods inside the view controller why not just update the view inside the method instead of passing it to another method?