2013-06-03 2 views
1

У меня есть класс, размещать твит в твиттер с помощью HTTP PostКак ждать затем выполнить действие, основанное на HTTPRequest ответ IOS

здесь немного кода PostTweet.h

@interface PostTweet : NSObject 
- (void)postMyTweet; 
@end 

PostTweet.m

- (void)postMyTweet 
{ 

    accountStore = [[ACAccountStore alloc] init]; 
    accountType = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter]; 
    [accountStore requestAccessToAccountsWithType:accountType options:nil completion:^(BOOL granted, NSError *error) 
    { 
     if (granted) 
     { 
      allAccounts = [accountStore accountsWithAccountType:accountType]; 

      if ([allAccounts count] > 0) 
      { 
       userAccount = [allAccounts objectAtIndex:0]; 
       userName = userAccount.username; 
       NSURL * reqURL = [NSURL URLWithString:ENDPOINT_MEDIA_UPLOAD]; 
       NSDictionary * parameter = [NSDictionary dictionaryWithObject:tweetTitle forKey:@"status"]; 

       SLRequest *twitterInfoRequest = [SLRequest requestForServiceType:SLServiceTypeTwitter 
                    requestMethod:SLRequestMethodPOST 
                       URL:reqURL 
                     parameters:parameter]; 
       [twitterInfoRequest addMultipartData:tweetImage withName:PARAM_MEDIA type:CONTENT_TYPE_MULTIPART_FORM_DATA filename:nil]; 

       [twitterInfoRequest setAccount:userAccount]; 

       [twitterInfoRequest performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) 
        { 
         //show status after done 
         long result = [urlResponse statusCode]; 



         //Let us say that every thing is ok and I got 200 response 
         if (result == 200) 
         { 
          NSLog(@"%ld",result); 
         } 




        } 
        ]; 
      } 
     } 
     else 
     { 
      NSLog(@"Not authorized"); 
     } 
    }]; 

} 

В моих viewcontroller.m

- (void) actuallySendTweet 
{ 
    PostTweet * pt = [[PostTweet alloc] init]; 

    [pt postTweet]; 
    NSLog(@"Done"); 
} 

Вопрос: после вызова метода TestMethod, как ждать ответа HTTP-запроса, и я могу сделать что-либо на основе ответа.

Что происходит, так это то, что как только я вызову testMethod, NSLog выполнит сразу же и не дожидается ответа HTTP.

+0

Вы действительно не хотите, чтобы ваш основной очереди, чтобы ждать ответа сети.Вы должны делать любое действие после твита, которое вы хотите в своем блоке завершения (где у вас есть этот NSW (@ "% ld", result); '). Эффективно, при асинхронном программировании вы должны отделить инициирование запроса от обработки ответа с сервера. Если это абсолютно необходимо, вы можете представить некоторый пользовательский интерфейс, который сообщает пользователю, что происходит фоновый материал (например, представление с помощью «UIActivityViewIndicator»), инициировать запрос и блокировать завершение 'performRequestWithHandler' удалить его. – Rob

+0

Технический ответ: «сделайте это в' performRequestWithHandler' », но если вы ищете менее абстрактный ответ, вы должны дать нам менее абстрактный вопрос. А именно, что именно вы хотите сделать после публикации этого твита? Нам может быть легче сделать конструктивные предложения, если вы скажете нам, что вы пытаетесь сделать. – Rob

+1

Я просто хочу показать сообщение завершения на основе результата запроса http. Например, если результат равен 200, появится сообщение MBProgressHUD с сообщением об успехе (я знаю, как сделать эту часть). Другие, тогда 200, выйдет сообщение об ошибке. @Rob – iMubarak

ответ

-1

Как здесь вы используете блок завершения. Нить не ждет выполнения блока. Так что вы хотите, что выполнение блока должен заполнить и прецессию данные до окончания выполнения метода, вы можете использовать,

dispatch_group_t 

Я издаю свой метод, который,

- (void)postMyTweet 
{ 

    accountStore = [[ACAccountStore alloc] init]; 
    accountType = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter]; 

    dispatch_group_t group = dispatch_group_create(); 

    dispatch_group_enter(group); 

    [accountStore requestAccessToAccountsWithType:accountType options:nil completion:^(BOOL granted, NSError *error) 
    { 
     if (granted) 
     { 
      allAccounts = [accountStore accountsWithAccountType:accountType]; 

      if ([allAccounts count] > 0) 
      { 
       userAccount = [allAccounts objectAtIndex:0]; 
       userName = userAccount.username; 
       NSURL * reqURL = [NSURL URLWithString:ENDPOINT_MEDIA_UPLOAD]; 
       NSDictionary * parameter = [NSDictionary dictionaryWithObject:tweetTitle forKey:@"status"]; 

       SLRequest *twitterInfoRequest = [SLRequest requestForServiceType:SLServiceTypeTwitter 
                    requestMethod:SLRequestMethodPOST 
                       URL:reqURL 
                     parameters:parameter]; 
       [twitterInfoRequest addMultipartData:tweetImage withName:PARAM_MEDIA type:CONTENT_TYPE_MULTIPART_FORM_DATA filename:nil]; 

       [twitterInfoRequest setAccount:userAccount]; 

       [twitterInfoRequest performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) 
        { 
         //show status after done 
         long result = [urlResponse statusCode]; 



         //Let us say that every thing is ok and I got 200 response 
         if (result == 200) 
         { 
          NSLog(@"%ld",result); 
         } 


         dispatch_group_leave(group); 
        } 
        ]; 
      } 
     } 
     else 
     { 
      NSLog(@"Not authorized"); 
      dispatch_group_leave(group); 
     } 
    }]; 

    dispatch_group_wait(group, DISPATCH_TIME_FOREVER); 
    dispatch_release(group); 

} 

Теперь из это вы можете получить.

+0

Очевидно, не делайте 'dispatch_group_wait' в главной очереди. – Rob

+0

Как передать результат ответа HTTP в viewcontroller .. ?? @Harsh – iMubarak

+0

есть некоторые методы, но (как говорит яблоко) Я бы рекомендовал вам написать собственный делегат. –

0

Во-первых, если вы хотите координировать две разные нити, dispatch_semaphore_t может быть более подходящим, чем dispatch_group_t.

Во-вторых, и что более важно, вы не должны брать асинхронный метод, такой как performRequestWithHandler, вызывать его из основной очереди синхронно. Вы никогда должны блокировать основную очередь.

К счастью, performRequestWithHandler дает нам блок handler, который мы можем использовать для выполнения действий после завершения твита. В ваших комментариях вы говорите, что просто хотите обновить свой HUD после твита, поэтому вы должны сделать это performRequestWithHandler (отправка этого обновления пользовательского интерфейса обратно в основную очередь, потому что, как сообщает the documentation, «обработчик не может быть вызван ни на какой конкретный поток "):

- (void)postMyTweet 
{ 
    ACAccountStore *accountStore = [[ACAccountStore alloc] init]; 
    ACAccountType *accountType = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter]; 
    [accountStore requestAccessToAccountsWithType:accountType options:nil completion:^(BOOL granted, NSError *error) 
    { 
     if (granted) 
     { 
      NSArray *allAccounts = [accountStore accountsWithAccountType:accountType]; 

      if ([allAccounts count] > 0) 
      { 
       ACAccount *userAccount = [allAccounts objectAtIndex:0]; 
       NSURL  *reqURL  = [NSURL URLWithString:ENDPOINT_MEDIA_UPLOAD]; 
       NSDictionary *parameter = [NSDictionary dictionaryWithObject:tweetTitle forKey:@"status"]; 

       SLRequest *twitterRequest = [SLRequest requestForServiceType:SLServiceTypeTwitter 
                   requestMethod:SLRequestMethodPOST 
                      URL:reqURL 
                    parameters:parameter]; 

       [twitterRequest addMultipartData:tweetImage withName:PARAM_MEDIA type:CONTENT_TYPE_MULTIPART_FORM_DATA filename:nil]; 
       [twitterRequest setAccount:userAccount]; 
       [twitterRequest performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) 
        { 
         if (error) 
          NSLog(@"tweet fail; error = %@", error); 
         else 
         { 
          long result = [urlResponse statusCode]; 

          if (result == 200) 
           NSLog(@"%ld",result); 
          else 
           NSLog(@"Unexpected response: %@", [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding]]); 
         } 

         // Dispatch UI updates back to main queue 

         dispatch_async(dispatch_get_main_queue(), ^{ 
          // do your MBProgressHUD stuff here 
         }); 
        }]; 
      } 
     } 
     else 
     { 
      NSLog(@"Not authorized"); 
     } 
    }]; 
} 

Вы также спросили:„Как я могу передать ответ HTTP привести к ViewController“? Очевидно, вы все это делаете в performRequestWithHandler, где у вас есть HTTP-ответ (и данные ответа).


Если вы хотите postTweet работать синхронно, то наилучшая практика подсказывает, что вы не представляете его из основной очереди (потому что, рискуя звучать как испорченную пластинку, вы не хотите, чтобы заблокировать основная очередь). Но вы могли бы иметь actuallySendTweet отправку твит от фоновой очереди, например .:

- (void) actuallySendTweet 
{ 
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
     PostTweet * pt = [[PostTweet alloc] init]; 

     [pt postTweetSynchronously]; 

     NSLog(@"Done"); 

     dispatch_async(dispatch_get_main_queue(), ^{ 
      // Now do any UI updates you want here. 

      // For example, do your MBProgressHUD update here. 
     }); 
    }); 
} 

- (void)postTweetSynchronously 
{ 
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); 

    ACAccountStore *accountStore = [[ACAccountStore alloc] init]; 
    ACAccountType *accountType = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter]; 
    [accountStore requestAccessToAccountsWithType:accountType options:nil completion:^(BOOL granted, NSError *error) 
    { 
     if (granted) 
     { 
      NSArray *allAccounts = [accountStore accountsWithAccountType:accountType]; 

      if ([allAccounts count] > 0) 
      { 
       ACAccount *userAccount = [allAccounts objectAtIndex:0]; 
       NSURL  *reqURL  = [NSURL URLWithString:ENDPOINT_MEDIA_UPLOAD]; 
       NSDictionary *parameter = [NSDictionary dictionaryWithObject:tweetTitle forKey:@"status"]; 

       SLRequest *twitterRequest = [SLRequest requestForServiceType:SLServiceTypeTwitter 
                   requestMethod:SLRequestMethodPOST 
                      URL:reqURL 
                    parameters:parameter]; 

       [twitterRequest addMultipartData:tweetImage withName:PARAM_MEDIA type:CONTENT_TYPE_MULTIPART_FORM_DATA filename:nil]; 
       [twitterRequest setAccount:userAccount]; 

       [twitterRequest performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) 
        { 
         // do whatever you want here, perhaps updating some class properties 

         // now that we're done, signal the semaphore 
         dispatch_semaphore_signal(semaphore); 
        }]; 
      } 
     } 
     else 
     { 
      NSLog(@"Not authorized"); 
      dispatch_semaphore_signal(semaphore); // make sure to signal here, too 
     } 
    }]; 

    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); 
} 
+0

Если вы вернетесь к моему основному вопросу, вы заметите, что я вызываю (postMyTweet) из класса viewcontroller.m. Метод, который обрабатывает перенос твита в твиттер, фактически находится в другом классе. Поэтому, когда я это называю, он выполняет свою работу, но NSLog @ «Done»; не дожидается, когда метод postMyTweet завершит и вернет результат ответа HTTP. Это мой вопрос: как заставить его ждать и вернуть результат ответа, тогда я могу сделать любое действие. Спасибо @Rob – iMubarak

+0

@iMubarak Ответ на вопрос «как заставить его подождать» - «вы можете сделать это с помощью семафоров, но это нецелесообразно сделать из основной очереди». Но я пересмотрел ответ, чтобы показать, как вы можете публиковать свой твиттер синхронно, но я также продемонстрирую, как убедиться, что вы не делаете этого в главной очереди, если хотите быть осторожным. – Rob