简体   繁体   中英

How to wait then perform an action based on HTTPrequest response iOS

I have class that post a tweet to twitter using HTTP Post

here is a bit of code 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");
         }
     }];

}

In my viewcontroller.m

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

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

The Question is: after calling The testMethod, How to wait for the http request response and I can do anything based on the response.

What happens now is that as soon as I call the testMethod the NSLog perform right away and does not wait for the http response.

First, if you wanted to coordinate two different threads dispatch_semaphore_t might be more appropriate than dispatch_group_t .

Second, and more importantly, you should not take an asynchronous method such as performRequestWithHandler , invoke it from the main queue in a synchronous manner. You never should be blocking the main queue.

Fortunately performRequestWithHandler gives us a handler block which we can use to perform actions after the tweet is done. In your comments, you say you simply want to update your HUD after the tweet, so you should do that performRequestWithHandler (dispatching that UI update back to the main queue, because, as the documentation says, "handler is not guaranteed to be called on any particular thread"):

- (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");
         }
     }];
}

You also asked "How can I pass the HTTP response result to the viewcontroller?" You obviously do all of this in performRequestWithHandler , where you have the HTTP response (and the response data).


If you want postTweet to operate synchronously, then best practices would dictate that you don't submit it from the main queue (because, at the risk of sounding like a broken record, you never want to block the main queue). But you could have actuallySendTweet dispatch this tweet from a background queue, eg:

- (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);
}

As here you are using completion block. The thread does not wait for the execution of block. So it you want that execution of block should complete and precess the data before finishing the execution of method, you can use,

dispatch_group_t

I am editing your method for that,

- (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);

}

Now from this you can get idea.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM