创建一个对象,并让它等到它的创建
问题描述:
好这里是我想要做的事:创建一个对象,并让它等到它的创建
我有一个由一些网络数据填充模型对象,我希望能够像创建这样的:
// createWithID will fire off a request to a server
MyObject *newObject = [MyObject createWithID:123];
if(newObject){
//do something!
}
我遇到的问题是createWithID方法中的网络调用是异步的,因此该方法将总是返回之前调用完成。
首先,这是一个好方法吗?我喜欢在该方法中封装网络呼叫的想法。其次,它可以在不阻塞主线程的情况下完成吗?
谢谢!
答
要在@ DANH的答案扩大一点,我会说,你不应该有一个指向对象,直到后它的全部完成。例如:
[MyObject makeObjectWithID:123 completion:^(MyObject *object, NSError *error) {
if (object == nil) {
NSLog(@"error creating object: %@", error);
} else {
NSLog(@"created object: %@", object);
}
}];
再创造的方法是这样的:
+ (void)makeObjectWithID:(NSInteger)objectID completion:(void(^)(MyObject*,NSError*))handler {
handler = Block_copy(handler);
dispatch_async(dispatch_get_global_queue(0,0), ^{
MyObject *object = [[MyObject alloc] initWithID:objectID];
NSError *error = nil;
BOOL succeeded = [object doTheExpensiveAndBlockingSetupThingWithError:&error];
if (succeeded == NO) {
[object release], object = nil;
}
dispatch_async(dispatch_get_main_queue(), ^{
handler([object autorelease], error);
});
});
Block_release(handler);
}
原则上,我发现了更安全的您做出API,就越有可能你会搞砸有些东西了。这种方式是安全的,因为你永远不会有一个指向部分构建的指针MyObject
。没有办法让你得到一个而不是完全可以使用。承认没有取消机制,但你仍然可以延长这一点,以允许这样做。
答
如果我理解你,MyObject发出一个异步请求来完成它的设置,所以调用者不能认为它创建的实例已准备好,直到异步设置完成。
解决此问题的方法是让调用者知道设置已完成。有几个好方法,包括使调用者成为MyObject的委托,或者让MyObject在完成时发布NSNotification,但我倾向于使用块,因为我发现它经常使得调用者的代码更易于阅读。
做到这一点的方法是这样的...在MyObject.h:
typedef void (^CompletionBlock)(id result, NSError *error);
+ (MyObject *)createWithId:(NSInteger)anId completion:(CompletionBlock)completion;
我的目标可以保持块作为伊娃是否需要(使用@property(副本... )),然后在安装完成时调用它。
现在主叫方将是这样的:
// do something to indicate activity, like show an activity indicator
MyObject *newObject = [MyObject createWithID:123 completion::^(id r, NSError *e) {
// hide the activity indicator
if (!error) {
// code here gets executed when newObject is ready... update the ui accordingly
}
}];
// code here gets executed right away, and should not assume that newObject is ready
等一下,你只是说你想***阻止主线?!? – 2012-04-07 02:13:26
我同意,阻止** MAIN **线程阻塞您的应用程序... – Sirens 2012-04-07 02:15:17
最好创建一个新线程,然后添加一个UIActivityIndictor或其他东西来显示网络调用正在进行中。 – Otium 2012-04-07 02:19:33