I am communicating with server in my ios app. I have following method in which I'm opening an alertview. I want to show a loading view while app is getting response from the server.
- (void) showDetailedQuestion:(id)sender
{
//loading view
self.loading_alert = [[UIAlertView alloc] initWithTitle:#"Loading\nPlease Wait..." message:nil delegate:self cancelButtonTitle:nil otherButtonTitles: nil];
[self.loading_alert show];
UIActivityIndicatorView *indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
// Adjust the indicator so it is up a few pixels from the bottom of the alert
indicator.center = CGPointMake(loading_alert.bounds.size.width / 2, loading_alert.bounds.size.height - 50);
[indicator startAnimating];
[self.loading_alert addSubview:indicator];
UIButton *btn = (UIButton*)sender;
int indx = btn.tag;
NSLog(#"tag:%d",indx);
answerAnQuestion *vc = [self.storyboard instantiateViewControllerWithIdentifier:#"Answer"];
vc.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal ;
vc.que_id = [self.que_id valueForKey:[NSString stringWithFormat:#"%d",indx]];
vc.qid_list = self.que_id;
vc.crnt = indx;
[self presentViewController:vc animated:YES completion:nil];
[self.loading_alert dismissWithClickedButtonIndex:0 animated:YES];
}
and in another answerAnQuestion.m
- (void)viewDidLoad
{
NSString *address = [NSString stringWithFormat:#"%#%#%#%#%#%#%#", path,#"questions/",que_id,#"?token=",token,#"&user_id=",usrId];
NSURL *URL = [NSURL URLWithString:address];
NSLog(#"%#",address);
[NSURLRequest setAllowsAnyHTTPSCertificate:YES forHost:[URL host]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL cachePolicy:NSURLCacheStorageAllowedInMemoryOnly
timeoutInterval:60.0];
[request setHTTPMethod:#"GET"];
responseData = [[NSMutableData alloc] init];
NSURLResponse *response = nil;
NSError *error = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if (data)
{
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*) response;
//If you need the response, you can use it here
int statuscode = [httpResponse statusCode];
NSString *responseMsg = [NSHTTPURLResponse localizedStringForStatusCode:statuscode];
NSLog(#" Status code: %d",statuscode );
NSLog(#" Status msg: %#",responseMsg );
}
else
{
// Handle error by looking at response and/or error values
NSLog(#"%#",error);
}
}
My problem is alertview is only shown up for a moment when view is changing. It suppose to open when I click the button. What could be the reason? how to solve this?
EDIT 1:
If i make asynchronous request to server then i'm not able to set those data in my tableview. I can set those data in my tableview Only if send synchronous request,but it blocks the app. Why this is happening ?
Any help will be appreciated.
Thank you.
You are sending SynchronousRequest on main thread, so it is blocking your UI thread. Read multithreading you will get various tutorial on this. I can suggest you to go for GCD or NSOperation and NSOperationQueue. Google for any of the above and you will get various sample for the same.
Or you can send asynchronous request as follows...
[NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
//Write code you want to call when data is received,
//Like dismissing loading view and populating UI.
}];
Updated:
//Display alert view, before sending your request..
[alertview show];
//send first request
[NSURLConnection sendAsynchronousRequest:request1 queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
//Write code you want to call when data is received,
//send second request
[NSURLConnection sendAsynchronousRequest:request2 queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
//Write code you want to call when data is received,
//send third request
[NSURLConnection sendAsynchronousRequest:request3 queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
//Write code you want to call when data is received,
//dismiss alert view on main thread
dispatch_async(getmainqueue, ^(void) {
// dismiss alert view...
});
}];
}];
}];
I have worked with Nuzhat Zari code, and I thank him for it, but also have experienced some issues with some core data operations between nested "sendAsynchronousRequest" (getting some weird thread and memory errors) so, my solution was unnest the calls to "sendAsynchronousRequest" and use some main thread variable validation.
#interface myMainThreadClass
#property (nonatomic,assign) NSInteger *currentAsyncTasks;
#end
#implementation
// Use init or viewDidLoad to make "currentAsyncTasks=0"!!
-(void)method
{
[self showLoadingAlert]; //or some ui update function
currentAsyncTasks++;
[NSURLConnection sendAsynchronousRequest:urlRequest queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
//do something with data
dispatch_async(dispatch_get_main_queue(), ^(void) {
[self dismissAlertInFinalTask]
});
}];
currentAsyncTasks++;
[NSURLConnection sendAsynchronousRequest:urlRequest2 queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
//do something with data
dispatch_async(dispatch_get_main_queue(), ^(void) {
[self dismissAlertInFinalTask]
});
}];
currentAsyncTasks++;
[NSURLConnection sendAsynchronousRequest:urlRequest3 queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
//do something with data
dispatch_async(dispatch_get_main_queue(), ^(void) {
[self dismissAlertInFinalTask]
});
}];
}
-(void)dismissAlertInFinalTask
{
currentNetworkTasks--;
if (currentNetworkTasks == 0)
{
[self dismissLoadingAlert];//or some ui update function;
}
}
#end
I also want to know if someone has managed to do multiple request using NSURLConnection delegate NSURLConnectionDataDelegate and ui calls.
Related
I am downloading cards from server using asynchronous request and I want the moment I finished downloading, I should be navigated to some other screen. I am downloading cards using this set of code.
NSMutableArray *array=[[NSMutableArray alloc]initWithObjects:[dictTemp objectForKey:#"image_1_url"],[dictTemp objectForKey:#"image_2_url"],[dictTemp objectForKey:#"image_3_url"], nil];
for(int i=0;i< [array count];i++)
{
NSURL* url = [NSURL URLWithString:[array objectAtIndex:i]];
NSURLRequest* request = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse * response,
NSData * data,
NSError * error) {
if (!error){
NSString *stringName=[NSString stringWithFormat:#"downloadimage%d",i+1];
UIImage *tempImage=[[UIImage alloc]initWithData:data];
[self saveLocally:tempImage andNAme:stringName];
}
[self performSelectorOnMainThread:#selector(update) withObject:nil waitUntilDone:YES];
}];
But the problem is, I am navigating to some other screen in update method, but it gets called before completion of asynchronous request.
I am downloading three images one by one using for loop as specified in the code, and I want to call update method after downloading all the three cards.
Thanks in advance
You can do the below if don't want want to change:
NSMutableArray *array=[[NSMutableArray alloc]initWithObjects:[dictTemp objectForKey:#"image_1_url"],[dictTemp objectForKey:#"image_2_url"],[dictTemp objectForKey:#"image_3_url"], nil];
NSInteger reqCounts = [array count];
for(int i=0;i< [array count];i++)
{
NSURL* url = [NSURL URLWithString:[array objectAtIndex:i]];
NSURLRequest* request = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse * response,
NSData * data,
NSError * error) {
if (!error){
NSString *stringName=[NSString stringWithFormat:#"downloadimage%d",i+1];
UIImage *tempImage=[[UIImage alloc]initWithData:data];
[self saveLocally:tempImage andNAme:stringName];
reqCounts --;
}
if (reqCounts == 0) {
[self performSelectorOnMainThread:#selector(update) withObject:nil waitUntilDone:YES];
}
}];
Better to check this awesome answer.
Instead of using the NSURLRequest class, the NSSession Object is recommended in iOS7. Try rewriting your code this way.
.......
NSURL* url = [NSURL URLWithString:[array objectAtIndex:i]];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDownloadTask *task = [session downloadTaskWithRequest:request completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
NSData *data = [[NSData alloc] initWithContentsOfURL:location];
NSArray *array = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
..........
}
dispatch_async(dispatch_get_main_queue(), ^{
//call your update method here
});
Hope it helps.
I have parsed json. The result of json stored in array which contain list of video ID.
Now I want to parse another json which retrieve detail of video and this json will be parsed in loop videoIDArray.count times
Here is code:
- (void)viewDidLoad
{
[super viewDidLoad];
videoIDArray = [[NSMutableArray alloc] init];
viewArray = [[NSMutableArray alloc] init];
//======Json Parsing
NSString *urlstring = [NSString stringWithFormat:#"https://myURL/youtubeList"];
NSURL *url = [NSURL URLWithString:urlstring];
NSURLRequest *Request = [NSURLRequest requestWithURL:url];
conn = [[NSURLConnection alloc] initWithRequest:Request delegate:self];
if (conn) {
webdata = [[NSMutableData alloc] init];
}
//==========
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
if (connection==conn) {
[webdata setLength:0];
}
if (connection==conn2) {
[webdata2 setLength:0];
}
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
if (connection==conn) {
[webdata appendData:data];
}
if (connection==conn2) {
[webdata2 appendData:data];
}
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
//-------conn getting list of videoID
if (connection == conn) {
NSString *str = [[NSString alloc] initWithBytes:[webdata bytes] length:[webdata length] encoding:NSUTF8StringEncoding];
NSDictionary *Result = [NSJSONSerialization JSONObjectWithData:[str dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil];
[videoIDArray addObjectsFromArray:[[[Result valueForKey:#"items"] valueForKey:#"id"] valueForKey:#"videoId"]];
NSLog(#"Video ID %#",videoIDArray);
//======conn2 is for getting detail of video base on videoID object
for (int i=0; i<videoIDArray.count; i++) {
NSString *urlstring = [NSString stringWithFormat:#"https://mydetailURL/videos/%#?v=2&alt=json",[videoIDArray objectAtIndex:i]];
NSURL *url = [NSURL URLWithString:urlstring];
NSURLRequest *Request = [NSURLRequest requestWithURL:url];
conn2 = [[NSURLConnection alloc] initWithRequest:Request delegate:self];
if (conn2) {
webdata2 = [[NSMutableData alloc] init];
}
}
//==========
}
if (connection==conn2) {
[MBProgressHUD hideHUDForView:self.view animated:YES];
[youtubeTableView reloadData];
NSString *str = [[NSString alloc] initWithBytes:[webdata bytes] length:[webdata length] encoding:NSUTF8StringEncoding];
NSDictionary *Result = [NSJSONSerialization JSONObjectWithData:[str dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil];
NSLog(#"ResultConn2 %#",Result);
[viewArray addObject:[[[Result valueForKey:#"entry"] valueForKey:#"yt$statistics"] valueForKey:#"viewCount"]];
NSLog(#"View Array %#",viewArray);
}
}
Problem is: it is not parsing as many times as in loop, only for last one connectionDidFinishLoading method called and crashed..
Can somebody tell me how to do this?
Is there any other way to do this?
EDIT
With AFNetworking
i changed my code like:
for (int i=0; i<videoArray.count; i++) {
[self parseWithUrl:[videoArray objectAtIndex:i]];
}
-(void)parseWithUrl: (NSString *)urlstr
{
NSString *tstr=[urlstr stringByReplacingOccurrencesOfString:#"\"" withString:#""];
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"https://myURL/feeds/api/videos/%#?v=2&alt=json",tstr]];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFJSONRequestOperation *operation =
[AFJSONRequestOperation JSONRequestOperationWithRequest: request
success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
//instead of NSLog i want to return result
NSDictionary *result = (NSDictionary *)JSON;
NSLog(#"VideoResult %#",result);
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
UIAlertView *av = [[UIAlertView alloc] initWithTitle:#"Error Retrieving Weather"
message:[NSString stringWithFormat:#"%#",error]
delegate:nil
cancelButtonTitle:#"OK" otherButtonTitles:nil];
[av show];
}];
[operation start];
}
I want to write:
-(NSDictionary *)parseWithUrl: (NSString *)urlstr
Is it possible?
if Yes then suggest me where i should return result?
if i want to call another method after completing json then where to write call code
here is my code:
[self getData:self.weather];
my method called number of times which i don't want.
success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
self.weather = (NSDictionary *)JSON;
[self getData:self.weather];
.....
.....
}
Your issue stems from the fact that each of these NSURLConnection connections run asynchronously and therefore you're running many requests concurrently, but your routine is using a single webData2, so your requests are tripping over each other.
If you want to stay with your current design, rather than having a for loop where you initiate all of the second set of requests, you should only request the first one. And then have the connectionDidFinishLoading for the second type of request initiate the next one. (You could manage this "next" process by keeping track of some numeric index indicating which request you're processing, incrementing it each time.)
But you ask how to do these requests sequentially, one after another. Is there any reason why you cannot do them concurrently (more accurately, when first request is done, then issue the detail requests for the individual videos concurrently). In that scenario, even better than the clumsy fix I outlined in the prior paragraph, a more logical solution is an NSOperation-based implementation that:
Uses a separate object for each connection so the individual requests don't interfere with each other;
Enjoys the concurrency of NSURLConnection, but constrains the number of concurrent requests to some reasonable number ... you will yield significant performance benefits by using concurrent requests; and
Is cancelable in case the user dismisses the view controller while all of these requests are in progress and you want to cancel the network requests.
If you're already familiar writing NSURLConnectionDataDelegate based code, wrapping that in an NSOperation is not much worse. (See Defining a Custom Operation Object in the Concurrency Programming Guide.) We can walk you through the steps to do that, but frankly much easier is to use AFNetworking. They've done the complicated stuff for you.
In your edit to your question, you ask whether it is possible to write:
- (NSDictionary *)parseWithUrl: (NSString *)urlstr
While it's technically possible to, you never want a method on the main queue waiting synchronously for a network request. If parseWithURL cannot do what it needs to do inside the success block of the AFNetworking call (e.g. you might initiate a [self.tableView reloadData] or whatever is needed for your UI), then have parseWithURL return the dictionary in a completion handler of its own, e.g.:
- (void)parseWithURL: (NSString *)urlstr completion:(void (^)(NSDictionary *))completion
{
...
AFJSONRequestOperation *operation =
[AFJSONRequestOperation JSONRequestOperationWithRequest: request
success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
completion(JSON); // call the completion block here
} failure:...];
}
Finally I am done parsing synchronous multiple json parsing with help of AFNetworking
Success of json parsing call another method in AFNetworking done by: link
Here is Code:
- (void)getResponse:(void (^)(id result, NSError *error))block {
NSString *weatherUrl = [NSString stringWithFormat:#"%#weather.php?format=json", BaseURLString];
NSURL *url = [NSURL URLWithString:weatherUrl];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
// 2
AFJSONRequestOperation *operation =
[AFJSONRequestOperation JSONRequestOperationWithRequest:request
// 3
success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
//Success
block(JSON,nil); //call block here
}
// 4
failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
UIAlertView *av = [[UIAlertView alloc] initWithTitle:#"Error Retrieving Weather"
message:[NSString stringWithFormat:#"%#",error]
delegate:nil
cancelButtonTitle:#"OK" otherButtonTitles:nil];
[av show];
}];
// 5
[operation start];
}
calling will be:
[self getResponse:^(id result, NSError *error) {
//use result here
}];
In my iPhone app handling web service for storing and retrieving data.Now i am using the following code for web service handling.
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
[request setPostValue:#"1" forKey:#"id"];
[request setTag:100];
[request setDelegate:self];
[request startAsynchronous];
By this code i got response in 'requestFinished' method.My problem is web service response is very delay(depends upon internet speed).How to make response from web service very fast?Please help me.
I think you want to send json objects by post method..delay is depend on your server(how fast it handle request and response back) but i suggest you to use progress bar and blocks to handle network request..
loadingHUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
loadingHUD.labelText = NSLocalizedString(#"Downloading", nil);
loadingHUD.mode=MBProgressHUDModeAnnularDeterminate;
NSString *documentDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,YES) lastObject];
// Add your filename to the directory to create your saved file location
NSString* destPath = [documentDirectory stringByAppendingPathComponent:[fileName stringByAppendingString:#".mov"]];
NSURL *url = [NSURL URLWithString:mainURL];
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url];
NSMutableURLRequest *request = [httpClient requestWithMethod:#"POST" path:postURL parameters:postRequest];
NSLog(#"postRequest: %#", postRequest);
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.outputStream = [NSOutputStream outputStreamToFileAtPath:destPath append:NO];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSLog(#"Successfully downloaded file to %#",[[NSString alloc] initWithData:operation.responseData encoding:NSASCIIStringEncoding]);
// Give alert that downloading successful.
NSLog(#"Successfully downloaded file to %#", destPath);
NSLog(#"response: %#", operation.responseString); // Give alert that downloading successful.
// [self.target parserDidDownloadItem:destPath];
loadingHUD.detailsLabelText = [NSString stringWithFormat:#"%# %i%%",#"Downloading",100];
[loadingHUD hide:TRUE];
[DBHelper savePurchaseId:fileName];
[self movieReceived];
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
// Give alert that downloading failed
NSLog(#"Error: %#", error);
// [self.target parserDidFailToDownloadItem:error];
[loadingHUD hide:TRUE];
}];
[operation setDownloadProgressBlock:^(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite)
{
// Progress
progress = ((float)totalBytesWritten) / fileSize;
loadingHUD.progress = progress;
}];
[operation start];
}
We cant control the internet speed due to the different network provider or environment when the client is using your app.
But you can put your web-services to run in background without effecting your main function.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//code for webservices calling
dispatch_async(dispatch_get_main_queue(), ^{
//functions after your webservices done, for example reload the table or hide the loading bar.
});
});
I'm trying to refactor some NSJSONSerialization code so that it is not on the main thread. At the moment the app is a bit sluggish.
I would like to refactor this code to what I have below and am having problems with the syntax particularly with the error handling. For instance if I take my existing code (the requestData: method) and put it within
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
});
the table no longer loads any data.
thanks for any help.
-(void)requestData {
[HUD showUIBlockingIndicatorWithText:#"Fetching JSON"];
NSError *requestError = nil;
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL
URLWithString:kURL]];
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&requestError];
NSError *jsonParsingError = nil;
if (requestError)
{
NSLog(#"sync. request failed with error: %#", requestError);
}
else
{
// handle data
publicData = [NSJSONSerialization JSONObjectWithData:response
options:0
error:&jsonParsingError];
publicDataArray = [publicData objectForKey:#"data"];
}
/*
for(publicDataDict in publicDataArray) {
NSLog(#"data output is %#",[publicDataDict objectForKey:#"title"]);
}
*/
[self.mainTableView reloadData];
[HUD hideUIBlockingIndicator];
}
Here's the code I would like to use.
-(void)viewDidAppear:(BOOL)animated
{
[HUD showUIBlockingIndicatorWithText:#"Fetching Data"];
//1
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//code executed in the background
//2
NSData* ghData = [NSData dataWithContentsOfURL:
[NSURL URLWithString:kURL]
];
//3
NSDictionary* json = nil;
if (ghData) {
json = [NSJSONSerialization
JSONObjectWithData:ghData
options:kNilOptions
error:nil];
}
//4
dispatch_async(dispatch_get_main_queue(), ^{
//code executed on the main queue
//5
[self.tableView reloadData];
[HUD hideUIBlockingIndicator];
});
});
}
A lot of people assume that sending a process to the background will automatically rid their application of any sluggishness, this is a WRONG assumption. If you send a CPU intensive task to the background, it is going to block the CPU as well. For multi-threading to work in your favour, you have to be methodical about it.
Now onto your problem, the simplest solution is for you to use what Apple already provides, NSURLConnection is your best bet, NEVER Use [NSData dataWithContentsOfURL:] this is a definite no no.
It is not the NSJSONSerialization that is the problem, its the network request.
You have two options really.
1) Use NSRULConnection delegate method and place your JSON serialization methods in – connectionDidFinishLoading: delegate method
2) Use the block methods for NSURLConnection [NSURLConnection sendAsynchronousRequest: queue: completionHandler:] (My preferred choice)
-(void)viewDidAppear:(BOOL)animated
{
[HUD showUIBlockingIndicatorWithText:#"Fetching Data"];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if (!error) {
NSError *jsonError = nil;
NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&jsonError];
if (jsonError) {
NSLog(#"Error parsing JSON");
//Optionally display error message here
}else{
self.globalDictionary = jsonDict;
[self.tableView reloadData];
[HUD hideUIBlockingIndicator];
}
}else
{
NSLog(#"Error with request");
[HUD hideUIBlockingIndicator];
//Optionally display error message here
}
}];
}
Notes:
globalDictionary is an NSDictionary instance that populates the table.
So the possible guess wold be for this is probably the table reload method will be called earlier. so at the last you can reload the table as given below.
-(void)viewDidAppear:(BOOL)animated
{
[HUD showUIBlockingIndicatorWithText:#"Fetching Data"];
//1
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//code executed in the background
//2
NSData* ghData = [NSData dataWithContentsOfURL:
[NSURL URLWithString:kURL]
];
//3
NSDictionary* json = nil;
if (ghData) {
json = [NSJSONSerialization
JSONObjectWithData:ghData
options:kNilOptions
error:nil];
}
//4
[self performSelectorOnMainThread:#selector(reloadTable) withObject:nil waitUntilDone:NO];
});
}
and after this do like this.
-(void)reloadTable {
[self.tableView reloadData];
[HUD hideUIBlockingIndicator];
}
Also check if tableview datasource delegate methods are getting called if it is not getting called then set the UITableView delegate.
If you are refactoring your code, make use of functions. You should write a logic/code aimed at doing certain task in a separate function, and also your LOC in any function should not exceed more then 20, in normal cases.
Talking about your problem, it looks you have put it right but i am not seeing you defining the source of tableView, please check if you have converted the JSON to any container object viz dictionary or an array.
-(void)viewDidAppear:(BOOL)animated
{
[HUD showUIBlockingIndicatorWithText:#"Fetching Data"];
[self fetchData];
}
-(void)fetchData
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// switch to a background thread and perform your expensive operation
NSData* ghData = [NSData dataWithContentsOfURL:
[NSURL URLWithString:kURL]
];
NSDictionary* json = nil;
if (ghData)
{
json = [NSJSONSerialization
JSONObjectWithData:ghData
options:kNilOptions
error:nil];
}
dispatch_async(dispatch_get_main_queue(), ^{
// switch back to the main thread to update your UI
[self.tableView reloadData];
[HUD hideUIBlockingIndicator];
});
});
}
Try first in to refactor to convert the project for new architecture ARC, i post this in a old answer take a look here:
My Post
Hope this help you or give a idea to refactor your code ;)
I am using AFNetworking and creating a post request for which I require json feedback. The code below works however I have two main questions; where do I release the ActivityIndicator Manager? The second question is this code correct, being new I get confused with blocks so I really want to know if I am doing it right thing for optimum performance, even though it works.
NSURL *url = [NSURL URLWithString:#"mysite/user/signup"];
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url];
AFNetworkActivityIndicatorManager * newactivity = [[AFNetworkActivityIndicatorManager alloc] init];
newactivity.enabled = YES;
NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:
usernamestring, #"login[username]",
emailstring, #"login[email]",
nil];
NSMutableURLRequest *request = [httpClient requestWithMethod:#"POST" path:#"mysite/user/signup"parameters:params];
[httpClient release];
AFJSONRequestOperation *operation = [AFJSONRequestOperation operationWithRequest:request success:^(id json) {
NSString *status = [json valueForKey:#"status"];
if ([status isEqualToString:#"success"]) {
[username resignFirstResponder];
[email resignFirstResponder];
[self.navigationController dismissModalViewControllerAnimated:NO];
}
else {
UIAlertView *alert =[[UIAlertView alloc] initWithTitle:#"Login Unsuccessful"
message:#"Please try again"
delegate:NULL
cancelButtonTitle:#"OK"
otherButtonTitles:NULL];
[alert show];
[alert release];
}
}
failure:^(NSHTTPURLResponse *response, NSError *error) {
NSLog(#"%#", error);
UIAlertView *alert =[[UIAlertView alloc] initWithTitle:#"Login Unsuccessful"
message:#"There was a problem connecting to the network!"
delegate:NULL
cancelButtonTitle:#"OK"
otherButtonTitles:NULL];
[alert show];
[alert release];
}];
NSOperationQueue *queue = [[[NSOperationQueue alloc] init] autorelease];
[queue addOperation:operation];
NSLog(#"check");
}
Thank you very much for your help in advance :)
I know this question is a bit old, but I still wanted to contribute.
As steveOhh said, you should use [[AFNetworkActivityIndicatorManager sharedManager] setEnabled:YES] to turn on the activity network indicator. It is a singleton, and hence it doesn't require you to manually alloc-init and release. As to the other question, I noticed you are missing some parameters in your block calls, also, you can do this, which is much cleaner code:
NSURL *url = [NSURL URLWithString:#"mysite/user/signup"];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:[NSURLRequest requestWithURL:url] success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
// your success code here
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
// your failure code here
}];
[operation start]; // start your operation directly, unless you really need to use a queue
Why not use this instead?
[[AFNetworkActivityIndicatorManager sharedManager] setEnabled:YES];
Hence there's no need to alloc and init
Can't say much on the other codes, just started out learning objective-C and AFNetworking.. :)
Regards,
Steve0hh