2012-04-07 73 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 
相關問題