iOS MVC - How to pass data from model to controlle

2019-04-09 18:24发布

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:

  1. The view controller gets a text from the view (user input), and passes that text to the MethodA of the model.

  2. 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.

  3. MethodB parses the output and puts all the results into a NSMutableArray

  4. 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

5条回答
一夜七次
2楼-- · 2019-04-09 18:41

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.

查看更多
ゆ 、 Hurt°
3楼-- · 2019-04-09 18:45

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];
}
查看更多
Ridiculous、
4楼-- · 2019-04-09 18:50

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).

查看更多
爷、活的狠高调
5楼-- · 2019-04-09 18:57

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]

MyModels 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];
查看更多
Juvenile、少年°
6楼-- · 2019-04-09 19:02
-(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?

查看更多
登录 后发表回答