iOS MVC - 如何从模型传递数据到控制器?

4
我在这方面做了很多研究,但是我对我的问题感到困惑。我正在为 iOS 应用程序开发 Objective-C。
这是我的设置:
1. 视图控制器从视图中获取文本(用户输入),并将该文本传递给模型的 MethodA。 2. 模型中的 MethodA 处理输入文本并获取输出(例如,搜索该文本的 Google)。它使用 dispatch_async 方法执行搜索,该方法调用模型内的 MethodB 选择器。 3. MethodB 解析输出并将所有结果放入 NSMutableArray 中。 4. 我的问题是:如何将 NSMutableArray 传回视图控制器,以便我可以在视图上显示它?
抱歉,如果我的问题的答案非常简单/明显。我是 Objective-C 新手。

你在使用Core Data吗?我个人不确定我完全理解你的问题。MethodB是解析输出的方法吗? - runmad
1
抱歉,我的问题表述不清。方法A使用dispatch_async调用Web服务。dispatch_async的选择器在完成后调用方法B,该方法获取原始数据(NSData)。方法B从NSData解析JSON回复,并将结果放入NSMutableArray中。我没有使用Core Data。使用Core Data实现是否更好? - BlueChips23
MethodA和MethodB只是视图控制器中的方法吗? - runmad
1
不,它们在Model类中。 - BlueChips23
5个回答

7

每当我想进行异步处理并且需要将其返回到UI中时,我会采取以下两种方法之一:

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

在模型对象的.h文件中应该记录它在某些情况下会触发通知的内容,例如当模型的某个部分被更新时。当ViewController初始化模型对象时,让它将自己设置为所记录通知的观察者,并实现一个回调函数来更新UI。

2 delegation and @protocol

创建一个@protocol,例如@protocol FooModelUpdateDelegate,其中包含一个正确命名的方法,例如fooObjectDidUpdate:(Foo *)object;,然后模型类有一个委托属性,如id<FooModelUpdateDelegate> updateDelegate,并且ViewController将自己设置为该委托,我相信你可以想出其余的部分。


1
仅作补充,依我之见,块现在是更好的方法。 - runmad

3
我想传递一个委托对象,该对象响应选择器方法并使用处理后的数据调用此方法,将是实现程序所需的松耦合结构的良好方式。您是否熟悉这个概念?或者我需要为您找一些代码示例吗?
更新:代码示例 因此,我可能会使用调用类,例如MyViewController,来实现回调方法myCallbackMethod,如下所示:
-(void) myCallbakcMethod: NSMutableArray* array {
    //DoWhatever with the returned data
}

重点是在计算完成后将结果传回此方法。因此,在您调用MethodAMyViewController 中,您需要传递一个参考以处理结果,即self
//From this:
[MyModel methodA:param1]
//To:
[MyModel methodA:param1:self]

MyModelmethodAmethodB需要添加一个参数(id)delegate,并在调用之间传递它。

在准备好数据myArraymethodB中,进行以下调用:

    if([delegate respondsToSelector:@selector(myCallbackMethod:)]])
        [observer performSelector:@selector(myCallbackMethod:) withObject:myArray];

我认为这正是我试图实现的(在看到您的回复之前,我不确定是否可能)。代码示例肯定会帮助我。谢谢! - BlueChips23
这太棒了!那正是我想要的。 - BlueChips23

2

在你的视图控制器中:

    // 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
    ...
}

在您的模型中:

...
- (id)getSearchResult:(NSString *)searchKeyword receiver:(id)aReceiver action:(SEL)receiverAction {
    self.receiver = aReceiver;
    self.action = receiverAction;
    // some async actions
}

在异步响应接收器中:
    ...
    [self.receiver performSelector:self.action withObject:self];
}

你在哪里处理HTTP错误呢?能否给我一个更完整的例子?谢谢 :) - trillions
使用AFNetworking可以节省很多时间。它使用块(blocks)而不是选择器(selectors)。https://github.com/AFNetworking/AFNetworking/tree/master/Example/Classes - kalys.osmonov
谢谢!这就是我正在使用的。然后我把AFNetworking调用放到模型数据中,再次进行封装。在块内部,最初我触发通知...现在我通过向包装方法添加块来更改为对成功和失败块的调用。感谢您指引我走向正确的方向! - trillions

1
除非我误解了你的描述,否则它听起来像是你的“model”类正在做它不应该做的事情。在这种情况下,它至少完成了一些控制器的工作。我的建议是将methodA和methodB合并到视图控制器(或另一个控制器类)中。如果必要的话,方法B仍然可以设置“model”实例的NSMutableArray属性(如果不需要则跳过此步骤)。

0
-(void)methodA {
    NSMutableArray *someArray = ...
    [self methodB:someArray];
}

-(void)methodB:(NSMutableArray*)array {
    NSLog(@"%@", array);
    // do something with the array, like update the view
}

但是如果两者都是视图控制器内的方法,为什么不直接在该方法内更新视图,而要将其传递到另一个方法中呢?


这就是我的初始代码。我在我的ViewController中完成了所有这些工作。但我一直在阅读有关Model应该负责处理数据,特别是处理逻辑的内容,所以我想在Model中实现类似的功能。感谢您的回复。 - BlueChips23
不一定。在您的视图控制器中处理少量数据是可以的。但是如果您正在处理大量数据,则使用委托方法从模型向视图控制器进行通信。您还可以考虑使用块,它们非常棒。 - runmad
认同块是非常棒的。我在dispatch_async中使用它们,它们非常简单易用。我应该尝试将其用于从模型传递数据回另一个控制器。 - BlueChips23

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接