2012-04-07 15 views
0

オーケーを作成していますまで待つ必要があり:私が何をしようとしているであるオブジェクトを作成し、それがここ

私はいくつかのネットワークデータによって移入されたモデルオブジェクトを持って、私は次のようにそれを作成することができるようにしたいですこの:

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

} 

私がいる問題はcreateWithIDメソッド内ネットワーク呼び出しで非同期であるため、コールが完了する前にこの方法は常に返されます。

まず、これは大丈夫ですか?私は方法でネットワークコールをカプセル化するという考えが好きです。次に、メインスレッドをブロックせずに実行できますか?

ありがとうございます!

+0

あなたは***あなたが***メインスレッドをブロックしたいと言ったのですか? –

+0

** MAIN **スレッドがあなたのアプリケーションを妨害するのを阻止することに同意します... – Sirens

+1

新しいスレッドを作成し、UIActivityIndi​​ctorなどを追加してネットワークコールが進行中であることを示す方がよいでしょう。 – Otium

答えて

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に:それは(@property(コピーを使用する必要がある場合

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

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

私のオブジェクトはIVARとしてブロックを維持することができます... ))、セットアップが完了したらそれを起動します。

今、呼び出し側は、次のようになります。

// 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 
関連する問題