在块内调用self以获取异步REST请求

时间:2014-04-29 18:16:09

标签: ios

我在[self userLoggedIn]区域内调用withBlock时遇到问题。它被调用,但它不显示TITHomeViewController。如果我将它移动到块的下方和外部,那么它可以正常工作。显然,我希望从withBlock内部调用它,因为它是异步REST请求的完成处理程序。

- (void)doAuth
{
    // Call the Facebook API /me method
    [FBRequestConnection startForMeWithCompletionHandler:
     ^(FBRequestConnection *connection, id result, NSError *error)
     {
         // Populate global Facebook user info
         self.fbAccessToken = [[[FBSession activeSession] accessTokenData] accessToken];
         self.fbUserID = [result objectForKey:@"id"];

         // Authenticate with the Titter API
         [self callAPI:@"auth" withBlock:^(NSDictionary *jsonData) {
             NSString *_id = [jsonData objectForKey:@"_id"];
             if (_id != nil) {
                 self.userID = _id;
                 [self userLoggedIn];
             }
         }];
     }];
}

- (void)userLoggedIn
{
    // Display the home view.
    self.window.rootViewController = [[TITHomeViewController alloc] initWithNibName:@"TITHomeViewController" bundle:nil];
}

- (void)callAPI:(NSString *)path withBlock:(void (^)(NSDictionary *jsonData))block
{
    // Initialize the API callback URL using global root and given path
    NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%@%@", apiRoot, path]];

    // The Titter API requires an authorization header formatted as [userID]@[accessToken]
    NSString *authorizationHeader = [NSString stringWithFormat:@"%@@%@", self.fbUserID, self.fbAccessToken];

    // Create the request and add our authorization header
    NSMutableURLRequest *restRequest = [[NSMutableURLRequest alloc] initWithURL:url];
    [restRequest addValue:authorizationHeader forHTTPHeaderField:@"authorization"];

    // Queue required for calling sendAsynchronousRequest
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];

    // Make an asynchronous request to our API and if there is no errors, return formatted JSON data to the passed block.
    [NSURLConnection
     sendAsynchronousRequest:restRequest
     queue: queue
     completionHandler:^(NSURLResponse *response,
                         NSData *data,
                         NSError *error) {
         if ([data length] >0 && error == nil) {
             NSLog(@"Succeeded! Data as string: %@", [NSString stringWithUTF8String:[data bytes]]);

             // Convert received JSON data into a NSDictonary object.
             NSDictionary *result = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil];

             // Call back the block passed in.
             block(result);
         }
         else if ([data length] == 0 && error == nil) {
             NSLog(@"Nothing was downloaded.");
         }
         else if (error != nil) {
             NSLog(@"Error = %@", error);
         }
     }];
}

1 个答案:

答案 0 :(得分:2)

上面的评论帖子让你大约90%的方式! UI在主线程上运行,并且应该在UI线程上对其进行任何更新。您可以通过在主线程上调用usedLoggedIn来解决阻塞代码:

dispatch_async(dispatch_get_main_queue(), ^{
  [self userLoggedIn];
});

值得注意的是,可能在块中使用self遇到问题:如果self消失,此块将失败。在这个用例中,这可能不是问题。你没有提到这段代码来自哪个类:如果它来自视图控制器,那么可以安全地假设它不会去任何地方。但是,如果它是一个辅助对象或类似的东西,它可能会在请求URL时(或在该逻辑中的某个位置)从你的下方消失。通常的做法是创建一个对self的弱引用,以便在块内使用,如下所示:

// Outside the block
MyViewController __weak *weakSelf = self;

// Inside the block
[weakSelf userLoggedIn];