我正在开发一个模型类,它提供从网络解析的数据。当然,我希望我的应用程序能够响应,因此网络应该在单独的线程/队列上完成。
这就引出了一个问题:我应该如何设计我的班级的@interface?
主要要求是:
- 它应该将数据从模型传递到视图控制器:);
- 它不应该阻塞主(UI)线程;
- 它应该很容易被其他开发人员理解和遵循。
根据我从 WWDC2012 视频中学到的内容,“在 iOS 上构建并发用户界面”Apple 建议将并发代码移动到使用模型的类本身。
假设我们有 Posts 类 (Posts.h/.m),它应该为 ViewController 提供 NSArray* 格式的最新帖子。
选项 I——并发在类用户中
该类本身不是并发的,但用户是:
//Posts.h:
@interface Posts : NSObject
- (NSArray*)getPostsForUser:(NSString*)user;
@end
//ViewController.m
@implementation ViewController
- (void)someFunctionThatUpdatesUI
{
//<...>
NSOperationQueue *q = [[NSOperationQueue alloc] init];
[q addOperationWithBlock:^{
NSArray *currentPosts = [Posts shared] getPostsForUser:@"mike";
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
//UI should be updated only on main thread
[self updateUIWithPosts:currentPosts];
}];
}];
//<...>
}
这种方法的主要缺点是必须在每个 ViewController 中重复几乎相同的代码。如果有几十个呢?
选项 II - 与完成处理程序模式的并发
我目前在我的应用程序中使用的第二个选项是完成处理程序模式。由于完成处理程序仅在执行了一些长时间的联网后才被调用,因此它不会阻塞主线程:
//Posts.h:
@interface Posts : NSObject
- (NSError*)getPostsForUser:(NSString*)user
withCompletionHandler:(void(^)(NSArray*))handler;
@end
@implementation Posts
- (NSError*)getPostsForUser:(NSString*)user
withCompletionHandler:(void(^)(NSArray*))handler
{
//<...>
dispatch_async(dipatch_get_global_queue(0, 0), ^{
//Do some may-be-long networking stuff here,
//parse, etc and put it into NSArray *result
dispatch_async(dipatch_get_main_queue(), ^{
handler(result);
});
});
//<...>
}
//ViewController.m
- (void)someFunctionThatUpdatesUI
{
//<...>
[Posts shared] getPostsForUser:@"mike"
withCompletionHandler:^(NSArray* posts){
//updateUI with posts
}];
}
从我的角度来看,这种方式很好,但@interface 相当复杂,方法名称很长并且(从我的角度来看)被混淆了。
选项三——委托模式
我看到的另一个选择是委托模式。困扰我的是,可能只有一个 ViewController 是代理,因此需要将每个 VC 都设置为代理 - viewWillAppear,这很容易忘记。
//Posts.h:
@protocol PostUpdate<NSObject>
- (void)updateUIWithPosts:(NSArray*)posts FromUser:(NSString*)user;
@end
@interface Posts
- (NSError*)updatePostsFromUser:(NSString*)user;
@property(nonatomic, weak) id<PostUpdate> delegate;
@end
//ViewController.m:
@implementation ViewController<PostUpdate>
- (void)viewWillAppear
{
//<...>
[Posts shared].delegate = self;
}
- (IBAction)getLatestsPostButtonPressed:(id)sender
{
[[Posts shared] updatePostsFromUser:@"mike"];
}
// protocol PostUpdate
- (void)updateUIWithPosts:(NSArray*)posts FromUser:(NSString*)user
{
//updating UI with posts
}
@end
所以这里有问题:
- 还有哪些模式适合以非阻塞方式将数据从模型传递到控制器的要求?
- 根据您的经验、实践或理论知识,您会推荐什么选项?