I need to know something about button and web service ,normally I'm use Uicollectionview for show data from web service by indexPath.item but if I don't use Uicollectionview It's possible? to pass and get data from web service.
Here's code
-(IBAction)ttButton:(id)sender
{
bookName = #"test";
bookVersion = [[bookList objectAtIndex:indexPath.row]bookVersion];// when I use this it's will crash.
_bookPosition = [[bookList objectAtIndex:indexPath.row]bookPosition];
bookId = #"1";
bookPath = #"test001";
pageAmount = 2;
mainMenu = #"test";
// downloadURL = [[bookList objectAtIndex:indexPath.row]downloadURL];
// pageAmount = [[bookList objectAtIndex:indexPath.row]pageAmount]; I want to go like this. but indexPath I can use only in collection view
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSString *stringURL = [NSString stringWithFormat:#"http://tlf/testdata/webservice/book_extract.php?main_menu=test&language=en&id=%#",(_bookPosition)];
NSURLResponse *response = nil;
NSError *error = nil;
NSURL *url = [NSURL URLWithString:stringURL];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
NSURLConnection *urlConnection = [[NSURLConnection alloc]init];
NSData *data = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:&response error:&error];
dispatch_async(dispatch_get_main_queue(), ^{
[self connection:urlConnection didReceiveResponse:response];
[self connection:urlConnection didReceiveData:data];
[db saveAssetVersion:_assetVersion];
if([db isDownloaded:bookId bookVersion:[bookVersion floatValue]]){
[self performSegueWithIdentifier:#"test" sender:self];
}
else{
[self startDownload];
}
});
});
}
Please Advice for any Idea. Thank you very very much.
I dont think you code to get the data is even being called in the case of Button. Anyway, you need to set the delegate of your NSURLConnection class to the class where fetching code is.
Essentially, there is no difference at all using UICollectionView or UIButton. That is just the difference of how user interacts with the system. The code to download and update should be seperate and should be called by both similarly.
Related
I have a problem with my application.It freeze for several second when I tap the sidebar menu.
What happen when I tapped menu is I pass string that gonna be url for json data fetch in my mainviewcontroller.Then it freeze because I fetch the data and populating data in tableview.
However I really new to ios programming,I wonder how can I remove the freeze?.
thanks in advance
here is my code snippet for the mainviewcontroller:
Don't use dataWiyhContentsOfURL:, or at least not directly on the main thread. If you block the main thread then the whole app stops working (as you see).
You need to learn about background threads and callback blocks, and look at using NSURLSession to download your data and then process it.
Instead of using dataWithContentsOfURL (which will block the main thread and so the UI) you need to start an asynchronous connection. In the IF ELSE change the two requests to something like below. The completionHandler (Block) is executed when done, the data parsed, HUD removed and table Updated.
You can even (and in fact must) do this within your cellForRowAtIndexPath for each of the images, however, I would use SDWebImage as it has a cache and is very easy to use.
There are also other methods if this is not right for you such as NSURLSession.
Some other points;
I have also noted that the HUD is stopped on every iteration of the FOR and probably should be outside.
I also can not see how your data is being loaded so I added a [myTable reloadData];
I can not see that the "dictionary" object is needed as it can be added directly to the array (see code)
// If you have the status bar showing
// [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
[HUD showUIBlockingIndicatorWithText:#"Please wait. . ."];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:kategori]];
[request setTimeoutInterval: 10.0];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue currentQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
{
// [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
if (data != nil && error == nil)
{
//All Worked
id jsonObjects = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
for (NSDictionary *dataDict in jsonObjects)
{
NSString *title_data = [dataDict objectForKey:#"title"];
NSString *thumbnail_data = [dataDict objectForKey:#"thumb"];
NSString *author_data = [dataDict objectForKey:#"creator"];
NSString *link_data = [dataDict objectForKey:#"link"];
[myObject addObject:[[NSDictionary alloc]initWithObjectsAndKeys:
title_data, title,
thumbnail_data, thumbnail,
author_data,author,
link_data,link,
nil]];
}
[HUD hideUIBlockingIndicator];
[myTableView reloadData];
}
else
{
// There was an error
}
}];
For the images something like (this is not tested). I am not sure what format your images are in but you should be able to just add it, this may need tweeking;
cell.imageView.frame = CGRectMake(0, 0, 80, 70);
__block UIImageView *cellImage = cell.imageView;
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[tmpDict objectForKey:thumbnail]]];
[request setTimeoutInterval: 10.0];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue currentQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
{
if (data != nil && error == nil)
{
//All Worked
cellImage.image = [[UIImage alloc]initWithData:data];
[cellImage layoutIfNeeded];
}
else
{
// There was an error
}
}];
You can start activity indicator and call fetch data method after few time...
- (void)viewDidLoad{
[activityIndicator startAnimating];
[self performSelector:#selector(fetchData) withObject:nil afterDelay:0.5];
}
- (void)fetchData{
Fetch your data over here
}
Or ideally you have to load data Asynchronous
For loading data Asynchronously check out the following link-
iphone-synchronous-and-asynchronous-json-parse
I Prefer MBProgressHUD.
Here is the link for 3rd Party API.
https://github.com/jdg/MBProgressHUD
Just copy these two files in your app.
MBProgressHUD.h
MBProgressHUD.m
Please guide me something about path.
NSIndexPath *index = [[self.collectionView indexPathsForSelectedItems]objectAtIndex:0];
_assetVersion = assetVer;
_bookPosition = [[bookList objectAtIndex:index.row]bookPosition];
_bookId = [[bookList objectAtIndex:index.row]bookID];
bookPath = [[bookList objectAtIndex:index.row]bookPath];
_downloadURLbook = [[bookList objectAtIndex:index.row]downloadURL];
NSLog(#"%#",_bookPosition);
cell.bookId = _bookId;
NSLog(#"%#",bookPath);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSString *stringURL = [NSString stringWithFormat:#"http://powershelf-dev.3viewsolution.com/dhl/webservice/book_extract.php?main_menu=%#&language=%#&id=%#",_checkType,_checkLang,(_bookPosition)];
NSURLResponse *response = nil;
NSError *error = nil;
NSURL *url = [NSURL URLWithString:stringURL];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
NSURLConnection *urlConnection = [[NSURLConnection alloc]init];
NSData *data = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:&response error:&error];
[self connection:urlConnection didReceiveResponse:response];
[self connection:urlConnection didReceiveData:data];
dispatch_async(dispatch_get_main_queue(), ^{
//code for check data
});
});
I don't know this one why alway crash like this
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[DownloadedBookDetail bookPosition]: unrecognized selector sent to instance 0x146cf4a0'
But when i go with image from web service it's work. if i use bookIndex = indexPath; without code
NSIndexPath *index = [[self.collectionView indexPathsForSelectedItems]objectAtIndex:0];
_assetVersion = assetVer;
_bookPosition = [[bookList objectAtIndex:index.row]bookPosition];
_bookId = [[bookList objectAtIndex:index.row]bookID];
bookPath = [[bookList objectAtIndex:index.row]bookPath];
_downloadURLbook = [[bookList objectAtIndex:index.row]downloadURL];
it's will work also. But i need to use data from database check data with Web service.
I need to use bookIndex = indexPath; with web service
I'm go check with this
if([db isDownloaded:bookName bookVersion:[bookVersion floatValue]]){
[self performSegueWithIdentifier:#"reader" sender:self];
}
else{
[self startDownload];
}
Thanks for any Idea.
In my app I will use the PSCollectionView, but it doesn't call the delegate method. I made so:
I read a JSON file
I parse this JSON to obtain name and image url
I connect the device to the image url to obtain width and height with the code you find at the end of this question
After this operation I need to call delegate method to obtain number of PSCollectionViewCell, to define the height of each cell and to fill the cell with image and name.
I implemented the delegate method, but it doesn't execute them. I guess my problem is because that when it want to create and define the characteristic of the cell the array who contains the information to fill the cell is still empty. How I can solve this?
CODE:
- (void) loadImageFromWeb:(NSString *)urlImg forName:(NSString*)name {
NSURL* url = [NSURL URLWithString:urlImg];
//NSURLRequest* request = [NSURLRequest requestWithURL:url];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
NSString *authCredentials =#"reply:reply";
NSString *authValue = [NSString stringWithFormat:#"Basic %#",[authCredentials base64EncodedStringWithWrapWidth:0]];
[request setValue:authValue forHTTPHeaderField:#"Authorization"];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse * response,
NSData * data,
NSError * error) {
if (!error){
image = [[UIImage alloc] initWithData:data];
imageWidth = image.size.width;
imageHeight = image.size.height;
imgWidth = [NSString stringWithFormat:#"%f", imageWidth];
imgHeight = [NSString stringWithFormat:#"%f", imageHeight];
self.dictWithDataForPSCollectionView = #{#"title": name,
#"width": imgWidth,
#"height": imgHeight};
[self.arrayWithData addObject:self.dictWithDataForPSCollectionView];
NSLog(#"DATA ARRAY: %#", self.arrayWithData);
} else {
NSLog(#"ERRORE: %#", error);
}
}];
}
Can anyone help me to fix this issue? Thank you!
your problem is that the delegate and the datasourse is called before that you set the array for fix your issue you have to reload the data when you set you array like that:
-(void)setArrayWithData:(NSArray *)arrayWithData{
if(_arrayWithData != arrayWithData){
_arrayWithData = arrayWithData;
}
[_yourCollectionView reloadData];
}
Make sure you connect the collectionview to your view controller by either doing myCollectionView.delegate = self;
OR
Control drag in interface builder from collectionview to view controller
So I normally write apps for android and just use an async task to call methods to run in the background while an alert dialog plays saying "Loading" or something like that. On this app Im trying to translate to iOS, Im parsing data from different websites and displaying a couple web images and I want to have my alart dialog play while all these things are being loaded. Ive been searching for hours and havent found the solution I am looking for. I was hoping someone could point me to a tutorial or somewhere in the right direction.
here is what im working with:
- (void) RSEpic{
NSURL * imageURL = [NSURL URLWithString:RSEimageURL];
NSData * imageData = [NSData dataWithContentsOfURL:imageURL];
UIImage * image = [UIImage imageWithData:imageData];
_RSEImage.image = image;
[self waterTemp];
}
- (void) waterTemp{
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
/* set headers, etc. on request if needed */
[request setURL:[NSURL URLWithString:#"http://waterdata.usgs.gov/usa/nwis/uv?02035000"]];
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:NULL error:NULL];
NSString *html = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSScanner *scanner = [NSScanner scannerWithString:html];
NSString *token = nil;
[scanner scanUpToString:#"<table id=\"table_12_00010\"" intoString:NULL];
[scanner scanUpToString:#" " intoString:&token];
NSArray *words = [token componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#":"]];
double temp = [words[1] doubleValue];
_waterTempC.Text = [NSString stringWithFormat:#"%.2f°C",temp];
_waterTempF.Text = [NSString stringWithFormat:#"%.2f°F",temp*9/5+32];
[self waterDepth];
}
- (void) waterDepth{
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
/* set headers, etc. on request if needed */
[request setURL:[NSURL URLWithString:#"http://waterdata.usgs.gov/va/nwis/uv?02037500"]];
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:NULL error:NULL];
NSString *html = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSScanner *scanner = [NSScanner scannerWithString:html];
NSString *token = nil;
[scanner scanUpToString:#"<table id=\"table_07_00065\"" intoString:NULL];
[scanner scanUpToString:#" " intoString:&token];
NSArray *words = [token componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#":"]];
double temp = [words[1] doubleValue];
_waterLevel.Text = [NSString stringWithFormat:#"%.2fFT",temp];
if (temp >= 9.0) {
_levelAlert.text = #"HIGH WATER PERMIT REQUIRED";
}
else if (temp >= 5.0){
_levelAlert.text = #"LIFE JACKET REQUIRED";
}
else {
_levelAlert.text = #"";
}
[self tempChart];
}
- (void) tempChart{
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
/* set headers, etc. on request if needed */
[request setURL:[NSURL URLWithString:#"http://waterdata.usgs.gov/nwis/uv/?dd_cd=12_00010&format=img_default&site_no=02035000&set_arithscale_y=on&period=7"]];
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:NULL error:NULL];
NSString *html = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSScanner *scanner = [NSScanner scannerWithString:html];
NSString *token = nil;
[scanner scanUpToString:#"http" intoString:NULL];
[scanner scanUpToString:#"\"" intoString:&token];
NSLog(#"%#",token);
NSURL * imageURL = [NSURL URLWithString:token];
NSData * imageData = [NSData dataWithContentsOfURL:imageURL];
UIImage * image = [UIImage imageWithData:imageData];
_chartImage.image = image;
}
- (void) depthChart{
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
/* set headers, etc. on request if needed */
[request setURL:[NSURL URLWithString:#"http://waterdata.usgs.gov/va/nwis/uv/?dd_cd=07_00065&format=img_default&site_no=02037500&set_arithscale_y=on&period=7"]];
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:NULL error:NULL];
NSString *html = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSScanner *scanner = [NSScanner scannerWithString:html];
NSString *token = nil;
[scanner scanUpToString:#"http" intoString:NULL];
[scanner scanUpToString:#"\"" intoString:&token];
NSLog(#"%#",token);
NSURL * imageURL = [NSURL URLWithString:token];
NSData * imageData = [NSData dataWithContentsOfURL:imageURL];
UIImage * image = [UIImage imageWithData:imageData];
_chartImage.image = image;
}
- (void) progressAlert {
// initialize our Alert View window without any buttons
baseAlert=[[UIAlertView alloc]initWithTitle:#"Please wait,\ndownloading updates...." message:nil delegate:self cancelButtonTitle:nil otherButtonTitles:nil];
// Display our Progress Activity view
[baseAlert show];
// create and add the UIActivity Indicator
UIActivityIndicatorView
*activityIndicator=[[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
activityIndicator.center=CGPointMake(baseAlert.bounds.size.width
/ 2.0f,baseAlert.bounds.size.height-40.0f);
// initialize to tell our activity to start animating.
[activityIndicator startAnimating];
[baseAlert addSubview:activityIndicator];
// automatically close our window after 3 seconds has passed.
[self performSelector:#selector(showProgressDismiss)withObject:nil afterDelay:3.0f];
}
- (void) showProgressDismiss
{
[baseAlert dismissWithClickedButtonIndex:0 animated:NO];
}
#end
So can someone tell me how to make my baseAlert Show and Dismiss while all this stuff is loading?
Use a dispatch_group_t, and once all threads have been completed, they can invoke notify, like so:
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
[self doAnExpensiveOperation];
});
dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
[self doAnotherExpensiveOperation];
});
dispatch_group_notify(group, dispatch_get_global_queue(0, 0), ^{
dispatch_async(dispatch_get_main_queue(), ^{
// called when both background threads have finished.
// Update UI elements here
});
});
To prioritize:
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
[self doAnotherExpensiveOperation];
});
The same concepts are applied on iOS as on Android: if you want to perform heavy computing and you want the app to be responsive do the heavy computing on a background thread and DO NOT ACCES UI FROM BACKGROUND THREADS. The only difference between the iOS and Android is the way you can perform tasks on background threads. Android has AsyncTasks or Loaders, iOS has NSOperations & NSOperationsQueue,GCD (grand central dispatch which is my favorite and the best solution in my opinion) or there are methods like performSelectorInBackground: which I don't like because is harder to return objects after thread is completed.
So my suggestion is, have a look over GCD (there are lots of other tutorials) and after that, change your code accordingly, if you have troubles changing the code or you have unexpected behaviors, come back to SO with other questions
Well, to make it simple and concise, you can tell your OS to execute some code in another thread with this:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//Insert your code here
});
The global queue means that you will submit a block to GCD, and the OS will execute that block in a convenient thread, except the main thread (where your UI runs). You must take care that if you want to update the UI (for example hide an alert, or stop an activity indicator), you need to do that in the main thread, (main_queue). So, a template we always use is as follows:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//Process your heavy code here.
dispatch_async(dispatch_get_main_queue(), ^{
//Update your UI here.
});
});
This is very important to avoid retain cycles if you're using ARC
As Apple says here, you have to use weak references to self inside a block, as so for any iVar you use inside a block whose retain count will be incremented.
I suggest the tutorial proposed by #danypata , it's a good one. In the same site you can find a lot of useful tutorials!!
Have a great day, and hope it helps!
I've followed some tutorials, but I'm stuck on doing Post requests. I Just want to send 3 parameters, to a URL and hadle with the response. And it has to be asynchronous, because it will give me some images, that i want to but one by one on the view.
Can you help me guys?
This is well covered here.
But the way I do it I find to be simpler, as I'll show you. Still there are many questions here on SO and other places that provide this knowledge.
First we set up our request with our parameters:
- (NSData *)executePostCall {
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"%#", YOUR_URL]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
NSString *requestFields = [NSString stringWithString:#""];
requestFields = [requestFields stringByAppendingFormat:#"parameter1=%#&", parameter1];
requestFields = [requestFields stringByAppendingFormat:#"parameter2=%#&", parameter2];
requestFields = [requestFields stringByAppendingFormat:#"parameter3=%#", parameter3];
requestFields = [requestFields stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSData *requestData = [requestFields dataUsingEncoding:NSUTF8StringEncoding];
request.HTTPBody = requestData;
request.HTTPMethod = #"POST";
NSHTTPURLResponse *response = nil;
NSError *error = nil;
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if (error == nil && response.statusCode == 200) {
NSLog(#"%i", response.statusCode);
} else {
//Error handling
}
return responseData;
}
This has to be wrapped up in a block since we can't execute this on the main thread because it will lock up our application and that is frowned upon, so we do the following to wrap this request up, I'll leave the rest of the details up to you:
dispatch_queue_t downloadQueue = dispatch_queue_create("downloader", NULL);
dispatch_async(downloadQueue, ^{
NSData *result = [self executePostCall];
dispatch_async(dispatch_get_main_queue(), ^{
// Handle your resulting data
});
});
dispatch_release(downloadQueue);
Use NSURLRequest. You can download files in the background and show them once you receive the delegate notification: Downloading to a Predetermined Destination