I have a code block for my NSURLConnection sendAsynchronousRequest, and when I try to set a UILabel's text, the text is never set, even though the values are there. Here's my code:
NSString *address = [addresses objectAtIndex:indexPath.row];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:#"http://myurl.com/%#", address]]];
[NSURLConnection sendAsynchronousRequest:urlRequest queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if ([data length] > 0 && error == nil)
{
NSString *dataOfData = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
if(![dataOfData isEqualToString:#"ERROR: address invalid"]) {
[balanceLabel setText:[NSString stringWithFormat:#"Balance: %#", dataOfData]];
if(data) {
qrCodeButton.alpha = 1;
}
} else {
errorLabel.text = #"This address is invalid.";
}
}
else if ([data length] == 0 && error == nil)
{
NSLog(#"Nothing was downloaded.");
[balanceLabel setText:#"Server Error, Please Try Again"];
}
else if (error != nil){
NSLog(#"Error = %#", error);
}
}];
Why is the UILabel's text never set? Is there a limitation to code blocks? If so, how would I fix my problem? Cheers!
It is because an NSOperationQueue is not the main thread. What you're doing is illegal. And the sad thing is that there is no need for it! Just say:
[NSURLConnection sendAsynchronousRequest:urlRequest
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
// ... and the rest exactly as you have it now
All fixed. Your request is asynchronous on a background thread, but when it comes back to you on the completion handler, you'll be on the main thread and able to talk to the interface etc.
Your code operates UI element should execute on main thread.
dispatch_async(dispatch_get_main_queue(), ^{
if ([data length] > 0 && error == nil)
{
NSString *dataOfData = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
if(![dataOfData isEqualToString:#"ERROR: address invalid"]) {
[balanceLabel setText:[NSString stringWithFormat:#"Balance: %#", dataOfData]];
if(data) {
qrCodeButton.alpha = 1;
}
} else {
errorLabel.text = #"This address is invalid.";
}
}
else if ([data length] == 0 && error == nil)
{
NSLog(#"Nothing was downloaded.");
[balanceLabel setText:#"Server Error, Please Try Again"];
}
else if (error != nil){
NSLog(#"Error = %#", error);
}
}) ;
Make sure errorLabel is not nil and the UILabel is visible (It is added in the view hierarchy and its frame is appropriate).
Related
I'm trying to figure out how to get MWphotobrowser to fetch photo, photo caption, photo thumbnail etc. from a json file an extermal server.
In viewDidLoad, I have this code:
- (void)viewDidLoad {
NSURL *url = [NSURL URLWithString:#"https://s3.amazonaws.com/mobile-makers-lib/superheroes.json"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[super viewDidLoad];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError)
{
NSLog(#"Back from the web");
}];
NSLog(#"Just made the web call");
}
In Case3 MWphotobrowser's Menu.m, I have the following code:
case 3: {
photo.caption = [self.result valueForKeyPath:#"name"];
NSArray * photoURLs = [self.result valueForKeyPath:#"avatar_url"];
NSString * imageURL = [photoURLs objectAtIndex:indexPath.row];
[photos addObject:[MWPhoto photoWithURL:[NSURL URLWithString:imageURL]]];
enableGrid = NO;
break;
}
Incase you missed it, the JSON file I'm using is https://s3.amazonaws.com/mobile-makers-lib/superheroes.json
Nothing I tweak seems to make it work, any ideas how to fix this?
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError)
{
// here make sure ur response is getting or not
if ([data length] >0 && connectionError == nil)
{
// DO YOUR WORK HERE
self.superheroes = [NSJSONSerialization JSONObjectWithData:data options: NSJSONReadingMutableContainers error: &connectionError];
NSLog(#"data downloaded.==%#", self.superheroes);
}
else if ([data length] == 0 && connectionError == nil)
{
NSLog(#"Nothing was downloaded.");
}
else if (connectionError != nil){
NSLog(#"Error = %#", connectionError);
}
}];
in here u r getting the response from server is NSArray -->NSMutableDictionary` so
Case scenario is
case 3: {
NSDictionary *superhero = [self.superheroes objectAtIndex:indexPath.row];
photo.caption = superhero[#"name"];
NSString * imageURL = superhero[#"avatar_url"];
// NSArray * photoURLs = superhero[#"avatar_url"];
[photos addObject:[MWPhoto photoWithURL:[NSURL URLWithString:imageURL]]];
enableGrid = NO;
break;
}
ur final out put is
I'm working on an update of an iOS app that another developer created. He was using ASIHTTPRequest to handle http requests. However, the version of the app I have to work with crashes. Since ASIHTTPRequest is not being updated anymore, I thought then that I should switch to using AFNetworking, but it's far too complicated for me to figure out.
So finally I thought I could just use NSURLConnection on its own.
Here is the original code that I'm trying to replace:
-(NSArray*)readUTF16LEFeed:(NSURL*) urlToRead{
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:urlToRead];
[request startSynchronous];
NSError *error = [request error];
if (!error) {
lastModified = [NSDate date];
NSData *response = [request responseData];//UTF-16LE
NSString* responseString = [[NSString alloc] initWithData:response encoding:NSUTF16LittleEndianStringEncoding];
DLog(#"string is: %#",responseString);
responseString = [responseString stringByReplacingOccurrencesOfString:#"ISO-8859-1" withString:#"UTF16-LE"];
NSData* data = [responseString dataUsingEncoding:NSUTF16LittleEndianStringEncoding];
return [self parseNamesFromXML:data];
}
return nil;
}
And here is what I'm trying to use instead:
-(NSArray*)readUTF16LEFeed:(NSURL*) urlToRead{
NSURLRequest *request = [NSURLRequest requestWithURL:urlToRead];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error ) {
if ([data length] >0 && error == nil)
{
// DO YOUR WORK HERE
lastModified = [NSDate date];
// NSData *response = [request responseData];//UTF-16LE
NSString* responseString = [[NSString alloc] initWithData:data encoding: NSUTF16LittleEndianStringEncoding];
DLog(#"string is: %#",responseString);
responseString = [responseString stringByReplacingOccurrencesOfString:#"ISO-8859-1" withString:#"UTF16-LE"];
NSData* data = [responseString dataUsingEncoding:NSUTF16LittleEndianStringEncoding];
return [self parseNamesFromXML:data];
}
else if ([data length] == 0 && error == nil)
{
NSLog(#"Nothing was downloaded.");
}
else if (error != nil){
NSLog(#"Error = %#", error);
}
}];
return nil;
}
However, I'm getting the error "Incompatible block pointer types sending NSArray to parameter of type void. And also "Control may reach end of non-void block."
How can I get this to work?
Make return type of your method as void. Dont return anything. Just call [self parseNamesFromXML:data]; method.
-(void)readUTF16LEFeed:(NSURL*) urlToRead{
NSURLRequest *request = [NSURLRequest requestWithURL:urlToRead];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error ) {
if ([data length] >0 && error == nil)
{
// DO YOUR WORK HERE
lastModified = [NSDate date];
// NSData *response = [request responseData];//UTF-16LE
NSString* responseString = [[NSString alloc] initWithData:data encoding: NSUTF16LittleEndianStringEncoding];
DLog(#"string is: %#",responseString);
responseString = [responseString stringByReplacingOccurrencesOfString:#"ISO-8859-1" withString:#"UTF16-LE"];
NSData* data = [responseString dataUsingEncoding:NSUTF16LittleEndianStringEncoding];
[self parseNamesFromXML:data];
}
else if ([data length] == 0 && error == nil)
{
NSLog(#"Nothing was downloaded.");
}
else if (error != nil){
NSLog(#"Error = %#", error);
}
}];
}
In parseNamesFromXML method, process your results and assign results array to a property. You can access it where ever you want.
-(void) parseNamesFromXML:(NSData *)xmlData
{
NSError *error;
//DLog(#"data is %#", [[NSString alloc] initWithData:xmlData encoding:NSUTF8StringEncoding ]);
GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithData:xmlData options:0 error:&error];
if (doc)
{
self.dataArray = [self parseXmlDoc:doc];
}
}
The completion block is called asynchronously, so by the time your code reaches return [self parseNamesFromXML:data]; the methods scope is already done (meaning the method returned nil.
Try using [NSURLConnection sendSynchronousRequest:returningResponse:error:] instead, since the original code is also synchronous.
Edit:
As Julian Król suggested, if you return something within a block, it will be counted as the return value of this block, not of the original method. But since the block does not have a return value, you'll get the compiler error.
I have a NSURLConnection (two of them), and they're running in the wrong order.
Here's my method:
- (void)loginToMistarWithPin:(NSString *)pin password:(NSString *)password {
NSURL *url = [NSURL URLWithString:#"https://mistar.oakland.k12.mi.us/novi/StudentPortal/Home/Login"];
//Create and send request
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
[request setHTTPMethod:#"POST"];
NSString *postString = [NSString stringWithFormat:#"Pin=%#&Password=%#",
[self percentEscapeString:pin],
[self percentEscapeString:password]];
NSData * postBody = [postString dataUsingEncoding:NSUTF8StringEncoding];
[request setHTTPBody:postBody];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
{
// do whatever with the data...and errors
if ([data length] > 0 && error == nil) {
NSError *parseError;
NSDictionary *responseJSON = [NSJSONSerialization JSONObjectWithData:data options:0 error:&parseError];
if (responseJSON) {
// the response was JSON and we successfully decoded it
NSLog(#"Response was = %#", responseJSON);
} else {
// the response was not JSON, so let's see what it was so we can diagnose the issue
NSString *loggedInPage = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"Response was not JSON (from login), it was = %#", loggedInPage);
}
}
else {
NSLog(#"error: %#", error);
}
}];
//Now redirect to assignments page
NSURL *homeURL = [NSURL URLWithString:#"https://mistar.oakland.k12.mi.us/novi/StudentPortal/Home/PortalMainPage"];
NSMutableURLRequest *requestHome = [[NSMutableURLRequest alloc] initWithURL:homeURL];
[request setHTTPMethod:#"POST"];
[NSURLConnection sendAsynchronousRequest:requestHome queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *homeResponse, NSData *homeData, NSError *homeError)
{
// do whatever with the data...and errors
if ([homeData length] > 0 && homeError == nil) {
NSError *parseError;
NSDictionary *responseJSON = [NSJSONSerialization JSONObjectWithData:homeData options:0 error:&parseError];
if (responseJSON) {
// the response was JSON and we successfully decoded it
NSLog(#"Response was = %#", responseJSON);
} else {
// the response was not JSON, so let's see what it was so we can diagnose the issue
NSString *homePage = [[NSString alloc] initWithData:homeData encoding:NSUTF8StringEncoding];
NSLog(#"Response was not JSON (from home), it was = %#", homePage);
}
}
else {
NSLog(#"error: %#", homeError);
}
}];
}
- (NSString *)percentEscapeString:(NSString *)string
{
NSString *result = CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
(CFStringRef)string,
(CFStringRef)#" ",
(CFStringRef)#":/?#!$&'()*+,;=",
kCFStringEncodingUTF8));
return [result stringByReplacingOccurrencesOfString:#" " withString:#"+"];
}
So, it's two NSURLConnection's that are added to the [NSOperationQueue mainQueue]. What my output is showing me is that the second NSURLConnection is running before the first one. So it tries to go to the page where I download data before I'm logged in, so it (obviously) returns a "You're not logged in" error.
How do I schedule them one after another?
The issue, as I suspect you have realized, is that you're doing asynchronous network requests (which is good; you don't want to block the main queue), so there's no assurance of the order they'll finish.
The quickest and easiest answer is to simply put the call to the second request inside the completion block of the first one, not after it. You don't want to be making that second one unless the first one succeeded anyway.
To keep your code from getting unwieldy, separate the login from the request for main page. And you can use the completion block pattern which is common with asynchronous methods. You add a parameter to loginToMistarWithPin that specifies what it should do when the request finishes. You might have one completion block handler for success, and one for failure:
- (void)loginToMistarWithPin:(NSString *)pin password:(NSString *)password success:(void (^)(void))successHandler failure:(void (^)(void))failureHandler {
NSURL *url = [NSURL URLWithString:#"https://mistar.oakland.k12.mi.us/novi/StudentPortal/Home/Login"];
//Create and send request
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
[request setHTTPMethod:#"POST"];
NSString *postString = [NSString stringWithFormat:#"Pin=%#&Password=%#",
[self percentEscapeString:pin],
[self percentEscapeString:password]];
NSData * postBody = [postString dataUsingEncoding:NSUTF8StringEncoding];
[request setHTTPBody:postBody];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
{
// do whatever with the data...and errors
if ([data length] > 0 && error == nil) {
NSError *parseError;
NSDictionary *responseJSON = [NSJSONSerialization JSONObjectWithData:data options:0 error:&parseError];
if (responseJSON) {
// the response was JSON and we successfully decoded it
NSLog(#"Response was = %#", responseJSON);
// assuming you validated that everything was successful, call the success block
if (successHandler)
successHandler();
} else {
// the response was not JSON, so let's see what it was so we can diagnose the issue
NSString *loggedInPage = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"Response was not JSON (from login), it was = %#", loggedInPage);
if (failureHandler)
failureHandler();
}
}
else {
NSLog(#"error: %#", error);
if (failureHandler)
failureHandler();
}
}];
}
- (void)requestMainPage {
//Now redirect to assignments page
NSURL *homeURL = [NSURL URLWithString:#"https://mistar.oakland.k12.mi.us/novi/StudentPortal/Home/PortalMainPage"];
NSMutableURLRequest *requestHome = [[NSMutableURLRequest alloc] initWithURL:homeURL];
[requestHome setHTTPMethod:#"GET"]; // this looks like GET request, not POST
[NSURLConnection sendAsynchronousRequest:requestHome queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *homeResponse, NSData *homeData, NSError *homeError)
{
// do whatever with the data...and errors
if ([homeData length] > 0 && homeError == nil) {
NSError *parseError;
NSDictionary *responseJSON = [NSJSONSerialization JSONObjectWithData:homeData options:0 error:&parseError];
if (responseJSON) {
// the response was JSON and we successfully decoded it
NSLog(#"Response was = %#", responseJSON);
} else {
// the response was not JSON, so let's see what it was so we can diagnose the issue
NSString *homePage = [[NSString alloc] initWithData:homeData encoding:NSUTF8StringEncoding];
NSLog(#"Response was not JSON (from home), it was = %#", homePage);
}
}
else {
NSLog(#"error: %#", homeError);
}
}];
}
Then, when you want to login, you can do something like:
[self loginToMistarWithPin:#"1234" password:#"pass" success:^{
[self requestMainPage];
} failure:^{
NSLog(#"login failed");
}];
Now, change those successHandler and failureHandler block parameters to include whatever data you need to pass back, but hopefully it illustrates the idea. Keep your methods short and tight, and use completion block parameters to specify what an asynchronous method should do when it's done.
Can you check the below link. It is about forcing one operation to wait for another.
NSOperation - Forcing an operation to wait others dynamically
Hope this helps.
This seems such an easy task, at least it is in VB.net. I simply need to reference an array based on a string that is passed to a method. When a view controller loads a method is called and a string is passed. A URL will be created based on this string and JSON will be fetched from it. What I want is for the method to populate an appropriate array based on this passed string.
Here we see the method "goGetData" being called in class "getData" with one of three string parameters "workshop/speaker/exhibitor":
- (void)viewDidLoad
{
[getData goGetData:#"workshop"];
[getData goGetData:#"speaker"];
[getData goGetData:#"exhibitor"];
getData *getDataInstance = [[getData alloc] init];
NSArray *newTablesArray = getDataInstance.jsonAllTables;
NSLog(#"Json currently = %#", newTablesArray);
[super viewDidLoad];
[[self myTableView]setDelegate:self];
[[self myTableView]setDataSource:self];
arrayTable =[[NSMutableArray alloc]init];
}
For example if "goGetDate" is fired with "speaker" I would need the speaker data to be fetched and then the "_jsonSpeaker" array to be populated. Here is my attempt so far to reference and populate the arrays based on what string was passed in the method call:
#import "getData.h"
#implementation getData
+(void)goGetData:(NSString *)requestedTable
{
getData *getDataInstance = [[getData alloc] init];
[getDataInstance buildArray];
[getDataInstance fetchData:requestedTable];
}
-(void)buildArray{
// I tried putting the arrays in an array but still do no know how to reference them
_jsonAllTables = [[NSMutableArray alloc] initWithObjects:_jsonExhibitor, _jsonSpeaker, _jsonWorkshop, nil];
}
-(void)fetchData:(NSString *)requestedTable{
NSString *varCurrentTable;
varCurrentTable = [NSString stringWithFormat:#"_json%#", requestedTable];
NSString *requestedURL;
requestedURL = [NSString stringWithFormat:#"http://testapi.website.com/api/%#", requestedTable];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:requestedURL]];
[NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
{
if (response){
NSHTTPURLResponse *newResp = (NSHTTPURLResponse*)response;
if (newResp.statusCode == 200) {
// STUFF FOR TESTING NSLog(#"Response to request: %# is: %i GOOD", requestedURL, newResp.statusCode);
if ([data length] >0 && error == nil)
{
// STUFF FOR TESTING NSUInteger indexOfArray = [_jsonAllTables indexOfObject:varCurrentTable];
// STUFF FOR TESTING NSString *objectAtIndexOfArray = [_jsonAllTables objectAtIndex:indexOfArray];
// This is the part I think I am stuck on:
// "CURRENT TABLE TO BE POPULATED" = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
}
else if ([data length] == 0 && error == nil)
{
NSLog(#"Nothing was downloaded");
}
else if (error != nil)
{
NSLog(#"Error: %#", error);
}
} else if (newResp.statusCode == 404){
NSLog(#"Response to request: %# is: %i BAD - URL incorrect", requestedURL, newResp.statusCode);
} else {
// add more returned status error handling here
}
}else{
NSLog(#"No response received");
}
}];
}
#end
Thanks,
Added for clarification on what I am trying to achieve: To save a LOT of writing out the same thing over and over is the following possibly in Obj-c (please excuse the mish-mash of languages)
NSArray *ListOfTables = [NSArray arrayWithObjects:#"Speaker", #"Exhibitor", #"Workshop", nil];
For i as int = 0 to ListOfTables.count{
[self fetchData:(ListOfTables.objectAtIndex = i) withCompletion:^(NSArray* objects, NSError*error){
dispatch_async(dispatch_get_main_queue(), ^{
if (objects) {
self.(ListOfTables.objectAtIndex = i) = objects;
}
else {
NSLog(#"Error: %error", error);
}
});
}];
i++;
Next
};
Notice i don't call a separate method for each table, instead I call the same method but with different table name parameter each time. I can't seem to find a working example with such placeholders in Xcode.
You probably want a method which is asynchronous and returns the result via a completion handler:
typedef void(^completion_t)(NSArray* objects, NSError*error);
-(void)fetchData:(NSString *)tableName
withCompletion:(completion_t)completionHandler;
Usage:
- (void) foo {
[self fetchData:tableName1 withCompletion:^(NSArray* objects, NSError*error){
dispatch_async(dispatch_get_main_queue(), ^{
if (objects) {
self.table1 = objects;
}
else {
NSLog(#"Error: %error", error);
}
});
}];
[self fetchData:tableName2 withCompletion:^(NSArray* objects, NSError*error){
dispatch_async(dispatch_get_main_queue(), ^{
if (objects) {
self.table2 = objects;
}
else {
NSLog(#"Error: %error", error);
}
});
}];
[self fetchData:tableName3 withCompletion:^(NSArray* objects, NSError*error){
dispatch_async(dispatch_get_main_queue(), ^{
if (objects) {
self.table3 = objects;
}
else {
NSLog(#"Error: %error", error);
}
});
}];
}
Implementation:
typedef void(^completion_t)(NSArray* objects, NSError* error);
-(void)fetchData:(NSString *)tableName
withCompletion:(completion_t)completionHandler
{
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:tableName]];
// Setup HTTP headers, e.g. "Accept: application/json", etc.
...
[NSURLConnection sendAsynchronousRequest:request
queue:[[NSOperationQueue alloc] init]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
{
NSError* err = error;
NSArray* objects; // final result array as a representation of JSON Array
if (response) {
NSHTTPURLResponse *newResp = (NSHTTPURLResponse*)response;
if (newResp.statusCode == 200) {
if ([data length] >0 && error == nil)
{
NSError* localError;
objects = ... // Use NSJSONSerialization to obtain a representation
if (objects) {
if (completionHandler) {
completionHandler(object, nil);
}
return;
}
else {
err = localError;
}
}
else {
err = ...
}
}
}
if (objects == nil) {
assert(err);
if (completionHandler) {
completionHandler(nil, err);
}
}
}];
}
Asynchronous Loop
Another example, for loading a bunch of data:
First, implemented a method which is an "asynchronous loop":
typedef void(^completion_t)(id result, NSError* error);
- (void) fetchObjectsWithTableNames:(NSMutableArray*)tableNames
completion:(completion_t)completionHandler;
This method is, itself asynchronous, thus the completion handler.
Usage:
- (void) foo
{
NSArray* tableNames = #[#"A", #"B", #"C"]; // possibly 1000
[self fetchObjectsWithTableNames:[tableNames mutableCopy]:^(id result, NSError*error){
if (error) {
NSLog(#"Error: %#", error);
}
else {
// finished fetching a bunch of datas with result:
NSLog(#"Result: %#", result);
}
}];
}
Implementation
- (void) fetchObjectsWithTableNames:(NSMutableArray*)tableNames
completion:(completion_t)completionHandler;
{
if ([tableNames count] > 0) {
NSString* name = [tableNames firstObject];
[tableNames removeObjectAtIndex:0];
[self fetchData:name withCompletion:^(NSArray* objects, NSError*error){
if (objects) {
[self.tables addObject:objects];
[self fetchObjectsWithTableNames:tableNames completion:completionHandler];
}
else {
// handle error
}
}];
}
else {
// finished
if (completionHandler) {
completionHandler(#"finished", nil);
}
}
}
I have this code to send a json string to a server
[NSURLConnection
sendAsynchronousRequest:req
queue:[[NSOperationQueue alloc] init]
completionHandler:^(NSURLResponse *response,
NSData *data,
NSError *error)
{
if ([data length] >0 && error == nil)
{
NSLog(#"Done");
}
else if ([data length] == 0 && error == nil)
{
NSLog(#"Nothing was downloaded.");
self.resultLabel.text=#"Done!";
self.view.userInteractionEnabled = TRUE;
}
else if (error != nil){
NSLog(#"Error = %#", error);
}
}];
The asynchronous request finishes fine and the logs show up almost immediately after it is finished. However, this code:
self.resultLabel.text=#"Done!";
self.view.userInteractionEnabled = TRUE;
Takes a good 10 seconds to show up in the UI. Anyone know why this would happen?
You must perform all UI changes in main thread:
....
if ([data length] == 0 && error == nil) {
dispatch_async(dispatch_get_main_queue(), ^{
self.resultLabel.text=#"Done!";
self.view.userInteractionEnabled = TRUE;
});
}
....