1
[NSURLConnection sendAsynchronousRequest:mutURLRequest queue:opQueue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
 {

     NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
     if(httpResponse.statusCode ==200)
     {
         [[NSNotificationCenter defaultCenter] postNotificationName:@"MUITCheckinPostSucceeded" object:self userInfo:postDictionary];
     }
 }];

This is my NSURLConnection and I'm not sure how to check if it was successful. I tried a simple flag but that did not work because the boolean didn't retain the "YES" value outside of the NSURLConnection. This is a school assignment so don't post the correct code I'd just like to know the method I need to implement or how I can tackle this problem in a way I haven't tried yet. Thanks in advance.

user2904379
  • 23
  • 1
  • 3
  • Checking the `NSError` value and the `statusCode` are the right ways to do this. Perhaps you can expand your code sample to show us how you're using this boolean value and we can help you further. In the absence of that, it's hard to comment on the behavior of your boolean value without seeing how you're using it. – Rob Oct 22 '13 at 15:53
  • I just simply had self.flag = YES; – user2904379 Oct 22 '13 at 15:57
  • I just simply had "self.flag = YES;" within the if statement above the NSNotificationCenter and I removed it because I wasn't sure if it was possible to keep the value of the flag if it was encapsulated within my NSURLConnection. What would the value of NSError be if the connection was unsuccessful. – user2904379 Oct 22 '13 at 16:05
  • Yes, you can update your view controller's properties within that completion block without incident (though be careful about updating variables from the `opQueue` ... in many cases you'll want to dispatch those updates back to the main queue). – Rob Oct 22 '13 at 16:14
  • what would the "NSError *error" be if it failed? – user2904379 Oct 22 '13 at 16:34
  • It would report a `NSError` if the server was down and/or not responsive. Or if the device didn't have any Internet connectivity at all. But if you had, for example, a 404 error (the server was found, but the web page wasn't), you wouldn't get an `NSError`. Hence, check _both_ the `NSError` and the `statusCode`. – Rob Oct 22 '13 at 17:07

2 Answers2

2

Try something like this:

[NSURLConnection sendAsynchronousRequest: myURLRequest 
                                   queue: [NSOperationQueue mainQueue]
                       completionHandler: ^(NSURLResponse *urlResponse, NSData *responseData, NSError *requestError) {
                           // Check for Errors
                           if (requestError || !responseData) {
                               // jump back to the main thread to update the UI
                               dispatch_async(dispatch_get_main_queue(), ^{
                                 [myLabel setText: @"Something went wrong..."];
                               });
                           } else {
                               // jump back to the main thread to update the UI
                               dispatch_async(dispatch_get_main_queue(), ^{
                                 [myLabel setText: @"All going well..."];
                               });
                           }
                       }
 ];
Axeva
  • 4,697
  • 6
  • 40
  • 64
  • This would work perfectly but I need to display the message within my view controller – user2904379 Oct 22 '13 at 16:26
  • @user2904379 then you change the NSLog to a label – meda Oct 22 '13 at 16:43
  • 1
    I've updated the example to update a UILabel based on the outcome of the operation. The dispatch block might be overkill, but depending on where this code is being executed, it's a safe way to ensure the UI updates take place on the main thread. – Axeva Oct 22 '13 at 16:45
  • By the way, I wouldn't give up on the checking of the `statusCode` of the response, as there are types of server-side errors that return a `responseData` and do not result in a `requestError` (e.g. a typo in the URL that results in a 404 - page not found error). – Rob Oct 22 '13 at 16:54
  • 1
    Not a bad idea, Rob. That would give full coverage. – Axeva Oct 22 '13 at 16:57
  • I would just update my UILabel but this is a separate class that does not have a view controller and I'm passing it to my view controller. I also have written to the API so I know that part works. I probably should have mentioned this earlier – user2904379 Oct 22 '13 at 17:07
0

You can update your class properties from the completion block. In this case, if flag was atomic, you can just update it. But if you're setting anything else (e.g. any object properties updated from the resulting data object), you might want to dispatch that back to the main queue to avoid synchronization issues:

self.flag = NO;

[NSURLConnection sendAsynchronousRequest:mutURLRequest queue:opQueue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
 {
     NSInteger statusCode = -1;

     // to be safe, you should make sure `response` is `NSHTTPURLResponse`

     if ([response isKindOfClass:[NSHTTPURLResponse class]])
     {
         NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
         statusCode = httpResponse.statusCode;
     }

     if (error)
     {
         // for diagnostic purposes only
         NSLog(@"%s: sendAsynchronousRequest error: %@", __FUNCTION__, error);
     }

     if (error == nil && statusCode == 200)
     {
         [[NSOperationQueue mainQueue] addOperationWithBlock:^{
             self.flag = YES;

             // set any other class properties here

             [[NSNotificationCenter defaultCenter] postNotificationName:@"MUITCheckinPostSucceeded" object:self userInfo:postDictionary];
         }];
     }
 }];

I notice that you're posting a notification. If you have multiple view controllers or model objects listening for that notification, that's fine and a notification makes sense. But if this code was in the view controller and that controller is the only thing that cares about the results, you generally forego the notification and just initiate the update the UI right from the code that's dispatched back to the main queue in that completion block.

One final caveat. Any references to self (or ivars, which have an implicit reference to self) will maintain a strong reference to the object for the duration of the operation (i.e. it will retain it). For example, if you dismiss the view controller while the network operation is in progress, the view controller won't be released until after the network operation is done. That's often fine (as it's just for the duration of the connection ... it's not the dreaded strong reference cycle), especially for a school assignment. But if that's an issue, there are techniques to only use a weak reference to the view controller inside the completion block, thus preventing the retaining of the view controller for the duration of the network operation. But that's beyond the scope of your original question (esp since it leads to a bunch of other questions about whether you want to cancel the network operation or not, when you dismiss the view controller), so I'll leave it at here.

Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • I still am getting a false value when it exits this block of code. – user2904379 Oct 22 '13 at 16:57
  • @user2904379 You're probably checking immediately after this block. But this network request occurs asynchronously, so `flag` will be set later, when your network request finishes (maybe seconds later). Add a `NSLog` inside that completion block and you'll see what I mean. But don't be tempted to use `sendSynchronousRequest` as you should never do synchronous network requests on the main queue. – Rob Oct 22 '13 at 16:59
  • So does this mean that I need to come up with a different solution other than a flag because I need to return this value and my if statement is within a different class – user2904379 Oct 22 '13 at 17:04
  • @user2904379 It's just a timing issue. It just means that you do all of your checking _inside_ the completion block (or in the code that is triggered in response to the notification), not in the code that immediately follows your initiation of the request. – Rob Oct 22 '13 at 17:12