2012-04-07 87 views
0

好这里是我想要做的事:创建一个对象,并让它等到它的创建

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

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

} 

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

首先,这是一个好方法吗?我喜欢在该方法中封装网络呼叫的想法。其次,它可以在不阻塞主线程的情况下完成吗?

谢谢!

+0

等一下,你只是说你想***阻止主线?!? – 2012-04-07 02:13:26

+0

我同意,阻止** MAIN **线程阻塞您的应用程序... – Sirens 2012-04-07 02:15:17

+1

最好创建一个新线程,然后添加一个UIActivityIndi​​ctor或其他东西来显示网络调用正在进行中。 – Otium 2012-04-07 02:19:33

回答

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。没有办法让你得到一个而不是完全可以使用。承认没有取消机制,但你仍然可以延长这一点,以允许这样做。

2

如果我理解你,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 
相关问题