0

好的,这就是我想要做的:

我有一个由一些网络数据填充的模型对象,我希望能够像这样创建它:

// createWithID will fire off a request to a server 
MyObject *newObject = [MyObject createWithID:123];
if(newObject){
   //do something!

}

我遇到的问题是 createWithID 方法中的网络调用是异步的,因此该方法将始终在调用完成之前返回。

首先,这是一种可行的方法吗?我喜欢在方法中封装网络调用的想法。二、不阻塞主线程能做到吗?

谢谢!

4

2 回答 2

3

为了稍微扩展@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. 你不可能得到一个并且没有完全准备好使用。当然,没有取消机制,但您仍然可以扩展它以允许这样做。

于 2012-04-07T03:21:16.993 回答
2

如果我理解你的话,MyObject 正在发出一个异步请求来完成它的设置,所以调用者不能假设它创建的实例已经准备好,直到异步设置完成。

解决这个问题的方法是让调用者知道设置已经完成。有一些很好的方法,包括让调用者成为 MyObject 的代表,或者让 MyObject 在完成后发布 NSNotification,但我倾向于使用块,因为我发现它通常会使调用者的代码更易于阅读。

这样做的方法是这样的......在 MyObject.h 中:

typedef void (^CompletionBlock)(id result, NSError *error);

+ (MyObject *)createWithId:(NSInteger)anId completion:(CompletionBlock)completion;

如果需要,我的对象可以将块保留为 ivar(使用 @property(copy...)),然后在设置完成时调用它。

现在调用者将如下所示:

// 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-07T02:54:00.860 回答