Display Image Through New Parse Config - ios

So I am using the new Parse Config for my application. The easy part was the installation of the NSString, but now I am working on the ImageView. Can someone help me figure out how to execute this?
Here is how I am calling for a NSString:
[PFConfig getConfigInBackgroundWithBlock:^(PFConfig *config, NSError *error) {
NSNumber *number = config[#"numberOne"];
textLabel.text = [number stringValue];
}];
Now I have created an Image called mainImage and I need this to set to mainImageFile from my Parse server. This is where I got stuck:
[PFConfig getConfigInBackgroundWithBlock:^(PFConfig *config, NSError *error) {
PFFile *pfFileMainImage = config[#"mainImageFile"];
//
//
}];
If this helps.. This is how I would set the images from Parse in tableView:
PFFile *thumbnail = [object objectForKey:#"imageFile"]; PFImageView
thumbnailImageView = (PFImageView)[cell viewWithTag:100]; thumbnailImageView.image = [UIImage
imageNamed:#"add-photo-placeholder.png"]; thumbnailImageView.file =
thumbnail; [thumbnailImageView loadInBackground];
Thank you!

Related

Receiveing array of Images from CoreData

I've created NSManagedObject* imagesArrayData that stores strings (paths) to images stored in the documents directory:
- (void)setImagesArray:(NSMutableArray *)imagesArray {
NSMutableArray* newImagesArray = [NSMutableArray new];
int i = 1;
for (UIImage* image in imagesArray) {
//generate path to createdFile
NSString* fileName = [NSString stringWithFormat:#"%#_%d", self.name, i];
NSString* filePath = [self documentsPathForFileName:fileName];
//save image to disk
NSData *imageData = UIImagePNGRepresentation(image);
[imageData writeToFile:filePath atomically:YES];
//add image path to CoreData
[newImagesArray addObject:filePath];
i++;
}
//set new value of imagesArray
imagesArrayData = [NSKeyedArchiver archivedDataWithRootObject:newImagesArray];
I am now not showing pathsToImages in header file, but property imagesArray:
-(NSMutableArray*) imagesArray {
NSMutableArray* images = [NSMutableArray new];
NSArray* imagePaths = [NSKeyedUnarchiver unarchiveObjectWithData:imagesArrayData];
for (NSString* imagePath in imagePaths) {
UIImage *image = [[UIImage alloc] initWithContentsOfFile: imagePath];
[images addObject:image];
}
return images;
The problem is, that whenever I want to get to [imagesArray objectatIndex:xxx], the imagesArray getter is called, and it takes time to recreate the full array. When trying to switch fast between images, the UI slows down.
What would be the elegant way to overcome this problem? Maybe creating another array full of images and updating it from time to time? Maybe something else? Please, help.
One thing you could do is refactor your getter to lazily load the array. If it is already defined, simply return it. If not, build it:
-(NSMutableArray*) imagesArray
{
if (!_imagesArray)
{
NSMutableArray* _imagesArray = [NSMutableArray new];
NSArray* imagePaths =
[NSKeyedUnarchiver unarchiveObjectWithData: imagesArrayData];
for (NSString* imagePath in imagePaths)
{
UIImage *image = [[UIImage alloc] initWithContentsOfFile: imagePath];
[_imagesArray addObject:image];
}
return _imagesArray;
}
I'm not sure what you mean about updating an array of images from time to time.
If your array of image names changes you will need some method to respond to those changes.

Images in UITableView keep re-loading and wrong images flash while scrolling

i have created a UITableView which populates each cell from URL requests. I have used 'dispatch_queue' to prevent the UItableView from freezing. For some reason when i scroll through the UITableView the images flash and disappear and fill the wrong cell for a second until fixing themselves. Here is my code. I am pulling the feed using restkit
customCell.customCellTextLabel.text = [NSString stringWithFormat:#"%#",feedO.title];
NSString *string = [NSString stringWithFormat:#"%#",feedO.body];
NSURL *urlString;
NSDataDetector *linkDetector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink error:nil];
NSArray *matches = [linkDetector matchesInString:string options:0 range:NSMakeRange(0, [string length])];
for (NSTextCheckingResult *match in matches) {
if ([match resultType] == NSTextCheckingTypeLink) {
urlString = [match URL];
NSLog(#"found Body URL: %# and title %#", urlString,feedO.title);
}
}
dispatch_queue_t imageQueue = dispatch_queue_create("imageDownloader",nil);
dispatch_async(imageQueue, ^{
NSData *data = [[NSData alloc] initWithContentsOfURL:urlString];
dispatch_async(dispatch_get_main_queue(), ^{
customCell.customCellImageView.image = [UIImage imageWithData: data];
});
});
return customCell;
You should consider using this library SDWebImage, available here https://github.com/rs/SDWebImage for that kind of problems. It handles asynchronous download and cache for remote images very easily.
The simpliest installation is done by using CocoaPods
CocoaPods (http://cocoapods.org) is a dependency manager for Objective-C, which automates and simplifies the process of using 3rd-party libraries in your projects.
See the Get Started section for more details.
Use in your Podfile
platform :ios, '6.1'
pod 'SDWebImage', '~>3.6'
After installing the dependency for SDWebImage, just simply use the following lines in your view controller :
#import <SDWebImage/UIImageView+WebCache.h>
...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *MyIdentifier = #"MyIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:MyIdentifier] autorelease];
}
// Here we use the new provided setImageWithURL: method to load the web image
[cell.imageView setImageWithURL:[NSURL URLWithString:#"http://www.domain.com/path/to/image.jpg"]
placeholderImage:[UIImage imageNamed:#"placeholder.png"]];
cell.textLabel.text = #"My Text";
return cell;
}
your code was missing one line , that i added.
customCell.customCellImageView.image =nil;
customCell.customCellTextLabel.text = [NSString stringWithFormat:#"%#",feedO.title];
NSString *string = [NSString stringWithFormat:#"%#",feedO.body];
NSURL *urlString;
customCell.customCellImageView.image =nil;
NSDataDetector *linkDetector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink error:nil];
NSArray *matches = [linkDetector matchesInString:string options:0 range:NSMakeRange(0, [string length])];
for (NSTextCheckingResult *match in matches) {
if ([match resultType] == NSTextCheckingTypeLink) {
urlString = [match URL];
NSLog(#"found Body URL: %# and title %#", urlString,feedO.title);
}
}
dispatch_queue_t imageQueue = dispatch_queue_create("imageDownloader",nil);
dispatch_async(imageQueue, ^{
NSData *data = [[NSData alloc] initWithContentsOfURL:urlString];
dispatch_async(dispatch_get_main_queue(), ^{
customCell.customCellImageView.image = [UIImage imageWithData: data];
});
});
return customCell;
The reason for this is the UITableView is reusing the cells created.
So firstly it creates lets say 10 of your CustomCell class.
Cell 0
Cell 1
...
Cell 9
By creating these 10 cells it will initiate 10 async calls to fetch images.
block 0 -> Cell 0
block 1 -> Cell 1
...
block 9 -> Cell 9
This will work fine if you don't scroll until all 10 downloads have finished.
But as soon as you start scrolling, the UITableView will start reusing the cells created and initiate new downloads.
So first it might reuse Cell 0 and create block 10 -> Cell 0.
If block 0 was not finished when Cell 0 was picked for reuse, you will now have two blocks wanting to put their image onto the same cell.
Leading to the following two scenarios:
Block 0 finishes first, then block 10
Block 10 finishes first, then block 0
This is what is causing the "flashing".
Then imagine scrolling through 1000s of cells within seconds :)
Solution
You need to be able to cancel the queued block for your cell being reused.
I would use e.g. SDWebImage or FastImageCache.
How you said. You catch the image in another thread, in order to prevent freezing. And in a tableView the cells are reused, and while in one background thread you are catching the new photo, in the main thread the cell with the previous photo is returned.
Here in the code I fix it and better explanation:
customCell.customCellTextLabel.text = [NSString stringWithFormat:#"%#",feedO.title];
NSString *string = [NSString stringWithFormat:#"%#",feedO.body];
NSURL *urlString;
NSDataDetector *linkDetector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink error:nil];
NSArray *matches = [linkDetector matchesInString:string options:0 range:NSMakeRange(0, [string length])];
for (NSTextCheckingResult *match in matches) {
if ([match resultType] == NSTextCheckingTypeLink) {
urlString = [match URL];
NSLog(#"found Body URL: %# and title %#", urlString,feedO.title);
}
}
// Here you need, at least quit the previous imagen, is better if you implement
// and activity indicator (here start), and also you should implement some imagen cache.
customCell.customCellImageView.image = nil;
// Apart from here, go to another thread.
dispatch_queue_t imageQueue = dispatch_queue_create("imageDownloader",nil);
dispatch_async(imageQueue, ^{
// this operation is slowly that return a cell, this happens after [1]
NSData *data = [[NSData alloc] initWithContentsOfURL:urlString];
dispatch_async(dispatch_get_main_queue(), ^{
//If you implement and activity indicator stop here.
customCell.customCellImageView.image = [UIImage imageWithData: data];
});
});
// [1] the cell is returned before the image is ready.
return customCell;
Above answer is correct. But no need to download image in cell for row. you can download image before table loading occurs in viewWillAppear or ViewDidLoad which fits to your requirement.
When you scroll your table every time your image will download again. to prevent this i prefer you to get image from cache and set in your imageview directly. so as per your code. if you scroll from 0 index to 10 then cell will download image for all 10 cells. after that if you scroll again 10 to index 0 . then image will be download again.
you can use (https://github.com/rs/SDWebImage) to download image async. its very easy and fast.
i prefered this library because it will handle your cache. just write below code
#import "UIImageView+WebCache.h"
// in cellForRowAtIndexPath.
[customCell.customCellImageView sd_setImageWithURL: [NSURL URLWithString:urlString]];
remove below code.
dispatch_queue_t imageQueue = dispatch_queue_create("imageDownloader",nil);
dispatch_async(imageQueue, ^{
NSData *data = [[NSData alloc] initWithContentsOfURL:urlString];
dispatch_async(dispatch_get_main_queue(), ^{
customCell.customCellImageView.image = [UIImage imageWithData: data];
});
});
Maybe this will help you.

object inside NSMutableArray

I've a tableview which has list of images and image thumbnail (image list and thumbnails are parsed from JSON object), I'm adding image data objects to imagesArray like this -
ImageData *imageDataObject = [[ImageData alloc]initWithImageId:[[imageListArray
objectAtIndex:indexPath.row] imageId] imageData:imageData];
[imagesArray addObject:imageDataObject];
ImageData object
#property (nonatomic, strong) NSString* imageId;
#property (nonatomic, strong) NSData* imageData;
allImagesArray like this
[ImageData object1,ImageData object2,....]
I want to assign imageData of the object from this array based on selectedImageId to
UIImage* image =[[UIImage alloc] initWithData:........];
I'm not able to think of a way to get to that imageData based on selectedImageId
Please help.
Update -
Thank you all for the help, I could do it.
One of the possible way will be, iterate through the array, find your selectedImageId from the dictionary and use it.
Example:
ImageData *imageDataObject = nil;
for(int i=0; i<allImagesArray.count;i++){
NSDictionary *dict= allImagesArray[i];
imageDataObject = [dict objectForKey:selectedImageId];
if(imageDataObject != nil){
UIImage* image =[[UIImage alloc] initWithData:........];
//do whatever
break;
}
}
As per your EDIT:
What you have is an array of ImageData objects [ImageData1,ImageData2,...]. For each ImageData object, you have imageId and imageData property and what you want is simply compare the selectedImageId with this imageId and get the imageData from that.
So for that, in your PPImageViewController, you can iterate the allImagesArray like this and get the imageData.
for(ImageData* imgDataObj in self.allImagesArray){
if([imgDataObj.imageId isEqualToString:self.selectedImageId]){
UIImage* image =[[UIImage alloc] initWithData:imgDataObj.imageData];
}
}
So you have:
NSArray* allImagesArray = #[#{#"some_image_id_in_NSString_1":#"the data in NSData 1"}, #{#"some_image_id_in_NSString_2":#"the data in NSData 2"}];
As a property of PPImageViewController.
Assuming the imageid is an NSString and imagedata is NSData, you can create a method something like this on PPImageViewController:
- (UIImage*) findSelectedImage
{
UIImage* selectedImage;
for(NSDictionary* d in allImagesArray)
{
NSString* currentKey = [[d allKeys] objectAtIndex:0];
if([currentKey isEqualToString:[self selectedImageId]])
{
NSData* imageData = [d objectForKey:currentKey];
selectedImage = [UIImage imageWithData:imageData];
break;
}
}
return selectedImage;
}
Then call it like this, maybe on your viewDidLoad method:
UIImage* selectedImage = [self findSelectedImage];
Hope it help.
I see you are adding ImageData objects directly into the Array. You could have just used a NSDictionary instead. The key can be imageID (assuming it to be unique) and value will be the imageData object. Then pass the dictionary instead of array to PPImageViewController.
NSMutableDictionary *imageData = [NSMutableDictionary dictionary];
ImageData *imageDataObject = [[ImageData alloc]initWithImageId:[[imageListArray
objectAtIndex:indexPath.row] imageId] imageData:imageData];
[imageData setObject:imageDataObject forKey:imageId];
And then within PPImageViewController, you can easily get the imageDataObject based on selected imageID like this:
ImageData *imageDataObject = allImagesDictionary[selectedImageID];
EDIT:
NSArray *imageIndexes = [allImagesDictionary allKeys];
// Now use imageIndexes to populate your table. This will guarantee the order
// Fetch the imageId
selectedImageID = imageIndexes[indexPath.row];
// Fetch the imageData
ImageData *imageDataObject = allImagesDictionary[selectedImageID];

Can't see image in my tableView which are coming from JSON

NSDictionary *temp = [self.placeArray objectAtIndex:[indexPath row]];
cell.textLabel.text = [temp objectForKey:#"name"];
UILabel *detailLbl = [[UILabel alloc]initWithFrame:CGRectMake(250,0,200,50)];
[detailLbl setText:[temp objectForKey:#"distance"]];
[cell.contentView addSubview:detailLbl];
cell.imageView.image =[UIImage imageNamed:[temp objectForKey:#"category"]];
On the last line i have set the image , but enable to see the image . please help me with this . And i can also not being able to unable segue .
when you loading image from URL but no local,your tableView has drawrect,so when the image finish loading,you must reload tableView or reload the row .
you can use lazy load to get your image. start an request to get image in background,and callback use an block to set image.
this links can help you:
https://github.com/rs/SDWebImage
How do you have define your cell? In some cases using:
initWithStyle:UITableViewCellStyleDefault
instead:
initWithStyle:UITableViewCellStyleValue1
had fixing the issue for me.
Try like this
NSString *imgUrl = #""; //enter your url here
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:imgUrl]];
UIImage *img = [UIImage imageWithData:data];
cell.imageView.image = img;

image not showing in UIImage from cached data

I cant possibly get the image that i parsed from the XML to show on my UIImageView using the code below. Am I doing something wrong because I checked it using NSLog to show if there is a link and apparently there is.
NSString *imageURL = [currentData.imageLink];
NSLog(#"this is link = %#", imageURL);
[cachedList addObject:imageURL];
[myCache setObject:cachedList forKey:#"imageURL"];
cachedList = [myCache objectForKey:#"imageURL"]; /where cachedList is NSMutableArray
for(id obj in cachedList){
NSLog(#"value = %#", obj); //to show value
cell.imageShow.image = [UIImage imageNamed:obj];
}
and also I tried doing the below code, but it gives me an error.
if (cachedList != nil) {
cell.imageShow.image = [UIImage imageNamed:[cachedList valueForKey:#"imageURL"]];
}
I think if you are using UITableView then this is the thing i have used and i prefer for tableview
Link: https://github.com/jakemarsh/JMImageCache

Resources