Display images from json (url of images) vlaue to CollectionView - objective-c

hi i tried to display images from json to CollectionView .
my code is...
NSMutableURLRequest *request=[NSMutableURLRequest requestWithURL:[NSURL URLWithString:#"http://zoo.com/jh/image.php"]];
[request setHTTPMethod:#"GET"];
[request setValue:#"application/json;charset=UTF-8" forHTTPHeaderField:#"content-type"];
NSError *err;
NSURLResponse *response;
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&err];
NSDictionary *jsonArray = [NSJSONSerialization JSONObjectWithData:responseData options: NSJSONReadingMutableContainers error: &err];
NSArray *headlines=[jsonArray1 objectForKey:#"image_gallery"];
for (int i=0;i<[headlines count]; i++)
{
NSString *moblinks=[[headlines objectAtIndex:i]objectForKey:#"image_url"];
[self.itemshowdetailsAr objectAtIndex:moblinks];
NSLog(#"%#",moblinks);
}
and my result in console
2014-06-20 15:05:27.005 Collection[3945:60b] http://xxxxxx/jh/ju_image/gal_1.jpg
2014-06-20 15:05:27.007 Collection[3945:60b] http://xxxxxx/jh/ju_image/gal_2.jpg
2014-06-20 15:05:27.007 Collection[3945:60b] http://xxxxxx/jh/ju_image/gal_3.jpg
2014-06-20 15:05:27.007 Collection[3945:60b] http://xxxxxx/jh/ju_image/gal_4.jpg
2014-06-20 15:05:27.008 Collection[3945:60b] http://xxxxxx/jh/ju_image/gal_5.jpg
2014-06-20 15:05:27.008 Collection[3945:60b] http://xxxxxx/jh/ju_image/gal_6.jpg
my collectionview code
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
CollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"Cell" forIndexPath:indexPath];
NSString *ImageURL =[self.itemshowdetailsAr objectAtIndex:indexPath.row];
NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:ImageURL]];
cell.imageView.image = [UIImage imageWithData:imageData];
cell.imageView.userInteractionEnabled=YES;
cell.imageView.contentMode = UIViewContentModeScaleToFill;
// cell.imageView.tag=i-1;
return cell;
}
but i got empty Collection View only.where i made mistake?i got array of url in console but cell is not displaying images.

By the looks of it you're trying to download image on the main thread and I'm guessing that the UI might be freezing while network requests are processed. Instead load the images asynchronously and away from the main thread by doing something like
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
CollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"Cell" forIndexPath:indexPath];
NSURLSession *session=[NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
[[session dataTaskWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:[self.itemshowdetailsAr objectAtIndex:indexPath.row]]] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
cell.imageView.image = [UIImage imageWithData:data];
cell.imageView.userInteractionEnabled=YES;
cell.imageView.contentMode = UIViewContentModeScaleToFill;
}];
}] resume];
return cell;
}
The NSURLSession task will run away from the main thread. The completion handler will be called when the imageData has been downloaded. At this point an operation is added to the main thread to update the imageView within your collectionViewCell.

Related

Search Bar and Search Display Controller not showing results after search

I am currently trying to figure out why a Search Bar and Search Display Controller is not displaying results after the user provides input.
1.) I'm very confident that the delegates and everything is configured correctly
2.) I have everything set up so I can see the console NSLog the data being reutrned
3.) This does not seem to produce anything:
-(void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText{
[self.searchDisplayController.searchResultsTableView reloadData];
}
4.) Data is added to NSMutableArray but just displays blank space
Other relating questions, there appears to be blank space at the bottom of these cells, why? Furthermore, besides searchBarCancelButtonClicked is there a way to detect when the search view/mode is dismissed? I have to change the status bar colour...
Any help would be greatly appreciated.
More code:
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
NSString *authorizedSearch = [searchBar.text stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLHostAllowedCharacterSet]];
NSString *post = [NSString stringWithFormat:#"search=%#",authorizedSearch];
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:#"%lu",(unsigned long)[postData length]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:[NSString stringWithFormat:#"blahblahblah/search.php"]]];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:postData];
NSURLConnection *conn = [[NSURLConnection alloc]initWithRequest:request delegate:self];
if(conn) {
NSLog(#"Connection Successful");
}else{
}
return YES;
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData*)data{
NSString *ret = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"DATA: %#", ret);
NSArray *objectArray=[NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
[resultsJson addObject:objectArray];
[resultsJson addObject:#"1"];
NSLog(#"results: %#",resultsJson);
NSLog(#"count: %i",[resultsJson count]);
}
What does your cellForRowAtIndexPath: look like?
Are you using:
[tableview dequeueReusableCellWithIdentifier:CellIdentifier];
or:
[tableview dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
Seems like there shouldn't be a difference, but I think there is.
Are you setting data properly for each backing store?
Could there be a race condition on results arriving and attempting to render them?
If you're sure the data is correct, could it be an autolayout (or similar) issue mashing up the frame? I've had that happen frequently and fix by adjusting everything in: -(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
See here for a possible reason on blank spaces at the bottom:
Stop UISearchDisplayController from showing empty cells

can't download image from web and how to check image from web

So I have this method to download an image from imgur.com as shown below:
- (void)getImageForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSURL *url=[NSURL URLWithString:[NSString stringWithFormat:#"i.imgur.com/%#.jpg",
[self.IDArray objectAtIndex:indexPath.row]]];
NSData * imageData = [[NSData alloc] initWithContentsOfURL:url];
self.imageTest = [UIImage imageWithData: imageData];
}
and then log the size of the data with this:
NSLog(#"%lx", (unsigned long)imageData.length);
but the size of the image in the log says
0
previously I use this asynchronous method:
- (void)getImageForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSURL *url=[NSURL URLWithString:[NSString stringWithFormat:#"i.imgur.com/%#.jpg",
[self.IDArray objectAtIndex:indexPath.row]]];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:urlRequest
queue:[NSOperationQueue currentQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
UIImage *imageMain = [UIImage imageWithData:data];
self.imageTest = [[UIImage alloc] init];
self.imageTest = [self imageWithImage:imageMain forRowAtIndexPath:indexPath];
}];
self.imageTest = [UIImage imageWithData: imageData];
}
but the log also says 0
yes the url exist. I have log it in another another method it is: i.imgur.com/EXtwoxT
What did I do wrong? how do I check that the image has been downloaded properly?

can't download image from web

So I have this method to download an image from imgur.com as shown below:
- (void)getImageForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSURL *url=[NSURL URLWithString:[NSString stringWithFormat:#"i.imgur.com/%#.jpg",
[self.IDArray objectAtIndex:indexPath.row]]];
NSData * imageData = [[NSData alloc] initWithContentsOfURL:url];
self.imageTest = [UIImage imageWithData: imageData];
}
and then log the size of the data with this:
NSLog(#"%lx", (unsigned long)imageData.length);
but the size of the image in the log says
0
previously I use this asynchronous method:
- (void)getImageForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSURL *url=[NSURL URLWithString:[NSString stringWithFormat:#"i.imgur.com/%#.jpg",
[self.IDArray objectAtIndex:indexPath.row]]];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:urlRequest
queue:[NSOperationQueue currentQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
UIImage *imageMain = [UIImage imageWithData:data];
self.imageTest = [[UIImage alloc] init];
self.imageTest = [self imageWithImage:imageMain forRowAtIndexPath:indexPath];
}];
self.imageTest = [UIImage imageWithData: imageData];
}
but the log also says 0
yes the url exist. I have log it in another another method it is: i.imgur.com/EXtwoxT you can see for yourself
What did I do wrong? how do I check that the image has been downloaded properly?
EDIT :
for those who says it's the URL you can see my actual log below. you can copy&paste the URL in your browser to see if it exist (it does)
- (void)getImageForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSURL *url=[NSURL URLWithString:[NSString stringWithFormat:#"i.imgur.com/%#.jpg",
[self.IDArray objectAtIndex:indexPath.row]]];
NSLog(#"i.imgur.com/%#.jpg", [self.IDArray objectAtIndex:indexPath.row]);
//Asynchronous handler
// NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
// [NSURLConnection sendAsynchronousRequest:urlRequest
// queue:[NSOperationQueue currentQueue]
// completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
// UIImage *imageMain = [UIImage imageWithData:data];
// self.imageTest = [[UIImage alloc] init];
// self.imageTest = [self imageWithImage:imageMain forRowAtIndexPath:indexPath];
// NSLog(#"%lx", (unsigned long)imageData.length);
// }];
//Synchronous handler
NSData * imageData = [[NSData alloc] initWithContentsOfURL:url];
self.imageTest = [UIImage imageWithData: imageData];
NSLog(#"%lx", (unsigned long)imageData.length);
}
2015-01-06 07:44:26.564 Huckleberry[12733:361944] i.imgur.com/EXtwoxT.jpg
2015-01-06 07:44:26.600 Huckleberry[12733:361944] 0
First off, your code is missing a protocol for the URL -- NSURL can handle different protocols and doesn't just default to http. Prefix http:// to your URL and see if that gets you some data.
Secondly, that URL isn't actually the URL of the image -- I believe that URL will return the whole HTML imgur page, which is most likely not what you want (since you're trying to create a UIImage with the data).
Instead, try looking into the Imgur API (https://api.imgur.com) -- there's even a link on that page to an example Obj-C library (https://github.com/geoffmacd/ImgurSession)

iOS segue too slow

I started working with iOS. And using Storyboard to navigate between the view controllers. First screen is an uiviewcontroller(login screen) and second one is an uiviewcontroller with a table view. I'm sending some web requests in the first viewcontroller and then performing segue to the next viewcontroller. There is about 9 seconds delay to load the second view controller after getting the response. I tried checking the cause using Timer profiler and didnt find anything in my obj-c code.
If anyone can help me here is the link to my trace file.
My Log:
2014-05-08 10:12:12.601 Consumer[6713:4207] One
2014-05-08 10:12:12.602 Consumer[6713:4207] Three
2014-05-08 10:12:12.605 Consumer[6713:4207] Four
2014-05-08 10:12:12.606 Consumer[6713:4207] Two
2014-05-08 10:12:21.394 Consumer[6713:60b] numberOfSectionsInTableView
2014-05-08 10:12:21.395 Consumer[6713:60b] titleForHeaderInSection
2014-05-08 10:12:21.395 Consumer[6713:60b] numberOfRowsInSection
2014-05-08 10:12:21.395 Consumer[6713:60b] titleForHeaderInSection
2014-05-08 10:12:21.395 Consumer[6713:60b] numberOfRowsInSection
2014-05-08 10:12:21.396 Consumer[6713:60b] titleForHeaderInSection
2014-05-08 10:12:21.396 Consumer[6713:60b] numberOfRowsInSection
2014-05-08 10:12:21.396 Consumer[6713:60b] cellForRowAtIndexPath
2014-05-08 10:12:21.399 Consumer[6713:60b] returning cell
2014-05-08 10:12:21.399 Consumer[6713:60b] cellForRowAtIndexPath
2014-05-08 10:12:21.400 Consumer[6713:60b] returning cell
2014-05-08 10:12:21.401 Consumer[6713:60b] cellForRowAtIndexPath
2014-05-08 10:12:21.402 Consumer[6713:60b] returning cell
2014-05-08 10:12:21.402 Consumer[6713:60b] titleForHeaderInSection
My LoginViewController:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([segue.identifier isEqualToString:#"login_success_new"]){
TableViewController *controller = (TableViewController *)segue.destinationViewController;
controller.municipalitiesArray = municipalitiesArray;
controller.muni_metergroup_dict = muni_metergroup_dict;
NSLog(#"Three");
}
}
-(void) sendPostRequest:(NSURL *)requestURL requestParams:(NSDictionary *)params requestType:(NSInteger)type{
NSError *error;
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:requestURL];
[request addValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
//[request addValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setHTTPMethod:#"POST"];
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
NSData *postData = [NSJSONSerialization dataWithJSONObject:params options:0 error:&error];
[request setHTTPBody:postData];
NSURLSessionDataTask *postDataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSLog(#"response = %#",json);
if(json != nil){
switch (type) {
case 1:
{
for (NSObject *object in [json objectForKey:#"municipalities"]){
MunicipalityModel *muniModel = [[MunicipalityModel alloc] init];
[muniModel setModelValues:object];
[municipalitiesArray addObject:muniModel];
}
//municipalitiesArray = [json objectForKey:#"municipalities"];
//MunicipalitiesModel *muniModel = [[MunicipalitiesModel alloc] init];
//[muniModel setModelValues:municipalitiesArray[0]];
userEmail = #"admin#example.com";
tokenValue = [json objectForKey:#"token"];
NSString *stringUrl = [NSString stringWithFormat:#"http://%#.quality.sentry-link.com/api/v1/meter_groups.json",[municipalitiesArray[count] muniSubdomain]];
NSURL *url = [NSURL URLWithString:stringUrl];
[self sendGetRequest:url requestParams:nil requestType:2];
break;
}
default:
break;
}
//[self performSegueWithIdentifier:#"login_success" sender:self];
}
}];
[postDataTask resume];
}
-(void) sendGetRequest:(NSURL *)requestURL requestParams:(NSDictionary *)params requestType:(NSInteger)type{
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:requestURL];
[request addValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request setHTTPMethod:#"GET"];
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
NSLog(#"Request URL =====> %#",requestURL);
NSURLSessionDataTask *getDataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSLog(#"response = %#",json);
if(json != nil){
switch (type) {
case 1:
{
break;
}
case 2:
{
NSMutableArray *meterGroupsArray = meterGroupsArray = [[NSMutableArray alloc] init];
for (NSObject *object in [json objectForKey:#"meter_groups"]){
MeterGroupModel *meterGroupModel = [[MeterGroupModel alloc] init];
[meterGroupModel setModelValues:object];
[meterGroupsArray addObject:meterGroupModel];
}
count++;
[muni_metergroup_dict setValue:meterGroupsArray forKey:[municipalitiesArray[count-1] muniSubdomain]];
if (count < [municipalitiesArray count]) {
NSString *stringUrl = [NSString stringWithFormat:#"http://%#.quality.sentry-link.com/api/v1/meter_groups.json",[municipalitiesArray[count] muniSubdomain]];
NSURL *url = [NSURL URLWithString:stringUrl];
[self sendGetRequest:url requestParams:nil requestType:2];
}
break;
}
default:
break;
}
if(count ==[municipalitiesArray count]){
NSLog(#"One");
[self performSegueWithIdentifier:#"login_success_new" sender:self];
NSLog(#"Two");
}
}
}];
[getDataTask resume];
}
TableviewController:
- (void)viewDidLoad
{
[super viewDidLoad];
//tableView.contentInset = UIEdgeInsetsMake(20, 0, 0, 0);
NSLog(#"Four");
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)buttonClicked:(id)sender{
NSLog(#"button Clicked");
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
NSLog(#"numberOfSectionsInTableView");
return [_municipalitiesArray count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
//Number of rows it should expect should be based on the section
NSString *sectionSubdomain = [_municipalitiesArray[section] muniSubdomain];
NSArray *array = [_muni_metergroup_dict objectForKey:sectionSubdomain];
NSLog(#"numberOfRowsInSection");
return [array count];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
NSLog(#"titleForHeaderInSection");
return [self.municipalitiesArray [section] muniName];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"cellForRowAtIndexPath");
long row = [indexPath row];
long section = [indexPath section];
NSArray *meterGroupArray = [_muni_metergroup_dict valueForKey:[_municipalitiesArray[section] muniSubdomain]];
static NSString *CellIdentifier = #"tableCell";
TableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:CellIdentifier
forIndexPath:indexPath];
// Configure the cell...
[cell.lblMeterGroupName setText:[meterGroupArray[row] groupName]];
[cell.lblMeterGroupId setText:[meterGroupArray[row] groupId]];
[cell.lblLatitude setText:[meterGroupArray[row] latitude]];
[cell.lblLongitude setText:[meterGroupArray[row] longitude]];
NSLog(#"returning cell");
return cell;
}
Thanks in advance!
The problem, clearly displayed in your log, is that One, Two, Three, and Four are being performed on a background thread. This means, for example, that you are saying:
[self performSegueWithIdentifier:#"login_success_new" sender:self];
...on a background thread. That is so wrong. You must NEVER say anything to or about the interface on a background thread. You need to get your threading straightened out. (The fact that One, Two, Three, and Four do not happen in order is also a clue that you may have set this up incoherently.)
EDIT: In a comment, you say that you now used dispatch_async(dispatch_get_main_queue()..., thus correctly moving the call to performSegueWithIdentifier: onto the main thread. Excellent! Your logging should now show that all calls connected with the interface (including especially "Three" in prepareForSegue:) are now on the main thread.
However, you still need to be careful. Basically everything in both completion: handlers happens on a background thread! You are even calling [self sendGetRequest:...] on a background thread! And you are apparently talking to instance variables of self on this a background thread. All of that is dangerous. What I would do is step out to the main thread right at the start of each completion handler, so that even if the completion handler is called on a background thread, everything I then do happens on the main thread.
Make sure that you are not performing your web request on the main thread which will block your UI and wait for the request to finish before performing the segue.

If UIImage not load from url

How can i add local image.png to cell if image not load from url?
- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"Cell";
DetailCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
NSURL* url = [NSURL URLWithString:[arrayOfImages objectAtIndex:indexPath.row]];
NSURLRequest* request = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse * response,
NSData * imagedata,
NSError * error) {
if (!error){
UIImage* image = [[UIImage alloc] initWithData:imagedata];
cell.flowerImage.image = image;
}
}];
return cell;
}
arrayOfImages - array of url strings that i've parsed from json.
You can check the image against nil to verify the image url.
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse * response,
NSData * imagedata,
NSError * error) {
if (!error){
UIImage* image = [[UIImage alloc] initWithData:imagedata];
if(!image) {
cell.flowerImage.image = [UIImage imageNamed:#"localImage"]; //local bundle image.
} else
cell.flowerImage.image = image;
} else {
cell.flowerImage.image = [UIImage imageNamed:#"localImage"];//local bundle image.
}
}];