0

私は今までブロックについてかなり読んできました.Appleのガイド、Cocoabuilder、SOに関する3つの記事と、基本的にオンラインチュートリアルから得たコードの例を使用しています。私はまだ1つの特定の質問を理解しようとしています. そこで、理解を深めるために、completionHandler の例だけでアプリを作成することにしました。これは私が思いついたものです:

ViewController

- (void)viewDidLoad
[SantiappsHelper fetchUsersWithCompletionHandler:^(NSArray *users) {
    self.usersArray = [NSMutableArray array];

    for (NSDictionary *userDict in users) {
        [self.usersArray addObject:[userDict objectForKey:@"username"]];
    }

    //WHILE TESTING postarray method, comment this out...
    //[self getPoints];
    [self.tableView reloadData];

}];

}

SantiappsHelper.h/m

typedef void (^Handler)(NSArray *users);


+(void)fetchUsersWithCompletionHandler:(Handler)handler {

NSString *urlString = [NSString stringWithFormat:@"http://www.myserver.com/myapp/getusers.php"];
NSURL *url = [NSURL URLWithString:urlString];

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:10];

[request setHTTPMethod: @"GET"];

__block NSArray *usersArray = [[NSArray alloc] init];


dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
//dispatch_async(dispatch_get_main_queue(), ^{
    // Peform the request
    NSURLResponse *response;
    NSError *error = nil;
    NSData *receivedData = [NSURLConnection sendSynchronousRequest:request
                                                 returningResponse:&response
                                                             error:&error];
    if (error) {
        // Deal with your error
        if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
            NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response;
            return;
        }
        NSLog(@"Error %@", error);
        return;
    }

    NSString *responseString = [[NSString alloc] initWithData:receivedData encoding:NSUTF8StringEncoding];

    usersArray = [NSJSONSerialization JSONObjectWithData:[responseString dataUsingEncoding:NSASCIIStringEncoding] options:0 error:nil];

    if (handler){
        //dispatch_sync WAITS for the block to complete before returning the value
        //otherwise, the array is returned but gets zeroed out
        dispatch_sync(dispatch_get_main_queue(), ^{
        handler(usersArray);
        });
    }
});
}

これが私が理解していることです...

  1. VC から fetchUsersWithCompletionHandler を呼び出し、この完了ブロックを渡します。そのブロックは NSArray ユーザー パラメータを受け取り、void を返します。

  2. 一方、SantiappsHelper クラスには、VC から受け取るタイプ ^block の handler と呼ばれる変数があります。

  3. fetchUsersWithCompletionHandler メソッドが実行され、その CompletionBlock パラメータを取得します。これは、NSArray users パラメータを取得しますか? 少し混乱します。

  4. webfetch は dispatch_async であるため、メイン スレッドをブロックしません。そのため、メイン スレッドでの実行が続行されます。その新しいスレッドはフェッチを同期的に実行し、その新しいスレッドは応答が返されるまで停止します。その新しいスレッドが応答を受信すると、NSHTTPURLResponse に入力します。返されると、usersArray に NSJSONSerialized データが入力されます。

  5. 最後に if テストに到達し、渡された PARAMETER ハンドラの存在をチェックしますか? 少し紛らわしいです...渡されたパラメーターは、completionBlock でした。そのハンドラーパラメーターは、渡されてから常に存在しているでしょうか?

  6. ハンドラが !NULL になると、実行がメイン スレッドに返され、ブロックによって期待される NSArray ユーザーが VC に返されます。

しかし、2 番目のディスパッチを非同期に変更すると、usersArray は適切に設定されますが、handler(usersArray) がメイン スレッドに送り返されると、空または nil になります。なんで?

4

1 に答える 1

2
  1. 正しい。これについて言う/考える最良の方法は、 と呼ばれるメソッドを呼び出していると言うことですfetchUsersWithCompletionHandler:。このメソッドはなくなり、何らかの作業を行い、将来のある時点で、ブロック リテラルで宣言したコードを実行し、ユーザーの配列を渡す可能性があります。

  2. handlerこのメソッドは、 typeという引数を受け取りますvoid (^)(NSArray *users)。この型は、呼び出されたときに配列を受け取り、結果を返さないコードのブロックを表します。

  3. fetchUsersWithCompletionHandler:いくつかの作業を行い、ある時点で、ブロック引数としてユーザーの配列で渡されたブロックを呼び出す場合があります。

  4. 正しい

  5. if (handler) {、ハンドラの引数が ではないかどうかを確認しますnil。ほとんどの場合、これは、常にfetchUsersWithCompletionHandler:ブロック リテラルを使用して呼び出す場合に特に当てはまり[self fetchUsersWithCompletionHandler:nil];ますnil。逆参照nilして呼び出しようとすると、クラッシュします。

  6. 実行はメイン スレッドに「戻される」のではなく、メイン スレッドで実行される作業ブロックをキューに入れるだけです。ブロックが完了するまでこのバックグラウンド スレッドをブロックする呼び出しでこれを行っていますdispatch_sync- これは実際には必要ありません。

配列は、 withストレージnilを宣言した結果である可能性があります。メソッドを呼び出すだけで、指しているものを変更していないため、これは必要ありません。usersArray__blockusersArray

于 2013-09-01T21:04:31.007 に答える