Loading Images from JSON to Xcode - objective-c

I having a bit difficulty loading images from a json file into UIImage - Table Cells in Xcode. I tried to load the images from the server into a NSArray then populating the table view UIImage cells. Is there something that I am missing here?
Image are located on a SQL server.
Thanks for the help.
Here is the server output from the PHP into Xcode. (cover_image)
(
"13497074790148.jpeg",
"13494650900147.png",
"13494606630147.png",
"13494605220147.jpeg",
"13494602920147.jpeg",
"13494601850147.jpeg",
"13491916300147.jpeg"
)
Here is the code in Xcode
NSArray *itemsimages = [[NSArray alloc]initWithArray:[results valueForKeyPath:#"cover_image"]];
self.itemImages = itemsimages;
Here is the code in table cells
UIImage *imageitm = [UIImage imageNamed: [self.itemImages objectAtIndex: [indexPath row]]];
cell.itmImage.image = imageitm;
return cell;

You don't have those images stored locally so it doesn't have any images to display. I suggest using SDWebImage to provide asyncronous image loading from remote location + caching mechanism.

-(void) viewDidLoad
{
NSURL *url = [NSURL URLWithString:#"YOUR URL"];
NSData *data = [NSData dataWithContentsOfURL:url];
NSError *error;
NSMutableDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
NSMutableArray *img = [[NSMutableArray alloc]init];
NSArray *websiteDetails = (NSArray *) [json objectForKey:#"logos"];
for(int count=0; count<[websiteDetails count]; count++)
{
NSDictionary *websiteInfo = (NSDictionary *) [websiteDetails objectAtIndex:count];
imagefile = (NSString *) [websiteInfo objectForKey:#"image_file"];
if([imagefile length]>0)
{
NSLog(#"Imagefile URL is: %#",imagefile);
[img addObject:imagefile];
}
}
//NSarray listofURL
listofURL = img;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"SimpleTableItem";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//this will start the image loading in bg
dispatch_async(concurrentQueue, ^{
NSURL *url = [NSURL URLWithString:[listofURL objectAtIndex:indexPath.row]];
NSData *image = [[NSData alloc] initWithContentsOfURL:url];
//this will set the image when loading is finished
dispatch_async(dispatch_get_main_queue(), ^{
cell.imageView.image = [UIImage imageWithData:image];
});
});
}
return cell;
}

You need to have a proper url in json response or you can store the common part of the url in the code itself and append it later with the image name returned from server.
I did as follows in the same condition
__autoreleasing NSError* error = nil;
id result = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
NSDictionary *dict = ((NSDictionary *) result)[#"result"];
NSString *url = dict[#"imageURL"];
NSData *imageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:url]];
UIImage *image = [[UIImage alloc] initWithData:imageData];
[_buttonImageView setImage:image forState:UIControlStateNormal];
where data is the response returned from server.

Related

Get UIImage from PHAsset (or assets-library://)

I'm trying to generate a UIImage from a PHAsset or assets-library. My code is this:
NSString *path = [self.options valueForKey:#"path"];
NSURL *localurl = [NSURL URLWithString:path];
NSData *data = [NSData dataWithContentsOfURL:localurl];
UIImage *image = [[UIImage alloc] initWithData:data];
But the UIImage is nil. I can set the path to be ph:// or assets-library://.
Thanks!
PHFetchOptions *allPhotosOptions = [PHFetchOptions new];
allPhotosOptions.sortDescriptors = #[[NSSortDescriptor sortDescriptorWithKey:#"creationDate" ascending:NO]];
PHFetchResult *allPhotosResult = [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeImage options:allPhotosOptions];
NSMutableArray *arrPhassets=[[NSMutableArray alloc]init];
[allPhotosResult enumerateObjectsUsingBlock:^(PHAsset *asset, NSUInteger idx, BOOL *stop) {
//here you will get phassets of images from the device photo library.you have to store it in the mutable array like this.
[arrPhassets addObject:asset];
}];
//here you will have array of phassets for images.
//now we will extract image from the phasset for one phasset.
PHAsset *as1=arrPhassets[0];
PHCachingImageManager *imagemanager=[[PHCachingImageManager alloc]init];
[imagemanager requestImageForAsset:as1 targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeAspectFit options:nil resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) {
//here "result" is the image for asset as1.
UIImage *image=result;
}];

Make lazy loading faster and responsive in iOS App

In my iOS app I've a class that performs a web request to get an array of informations located in mySQL DB. In this class I've a method that do this taking as input a mySQL query:
- (NSMutableArray *) myreq:(NSString *)query{
// Create NSData object
NSData *dataQuery = [query
dataUsingEncoding:NSUTF8StringEncoding];
// Get NSString from NSData object in Base64
NSString *base64EncodedQuery = [dataQuery base64EncodedStringWithOptions:0];
// Print the Base64 encoded string
NSLog(#"Encoded: %#", base64EncodedQuery);
NSMutableString *strURL = [NSMutableString stringWithFormat:#"http://…=%#“,base64EncodedQuery];
[strURL setString:[strURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSData *dataURL = [NSData dataWithContentsOfURL:[NSURL URLWithString:strURL]];
NSError* error;
NSDictionary* json = [NSJSONSerialization
JSONObjectWithData:dataURL
options:kNilOptions
error:&error];
NSMutableArray *results = [[NSMutableArray alloc] init];
int numRow = 0;
for (NSArray *arrow in json) {
[results addObjectsFromArray:arrow];
numRow++;
}
return results;
}
This method send a query to a php script that perform immediately this query to MySQL DB and get a json with results. I translate the json in this method and finally return an array with results.
I call myreq in a method
- (void)downloadScope{
_arrID = [[NSMutableArray alloc] init];
_arrIDUsers = [[NSMutableArray alloc] init];
_arrUsernames = [[NSMutableArray alloc] init];
_arrPictures = [[NSMutableArray alloc] init];
[myQueue addOperation:[NSBlockOperation blockOperationWithBlock: ^{
query = #"SELECT ID FROM mytable”;
[_arrID addObjectsFromArray:[self myreq:query]];
for (int i = 0; i < [_arrID count]; i++) {
NSArray *tempArray = [[NSArray alloc] initWithArray:[self myreq:[NSString stringWithFormat:#"SELECT IDUsr,usrn, pictureaddress FROM mytable WHERE ID = %#",_arrID[i]]]];
[_arrIDUsers insertObject:tempArray[0] atIndex:i];
[_arrUsernames insertObject:tempArray[2] atIndex:i];
[_arrPictures insertObject:tempArray[2] atIndex:i];
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[self.tableView reloadData];
}];
}
}]];
[myQueue setSuspended:NO];
}
In tableView I create cells in this way (using SDWebImage):
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//Identificatore di cella
NSString *identifier = #“cellmy”;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
cell.backgroundColor = nil;
if ( cell == nil ) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
}
NSString *username = [self.arrUsernames objectAtIndex:indexPath.row];
UILabel *cellLabelUsername = (UILabel *)[cell viewWithTag:2];
cellLabelUsername.text = [username uppercaseString];
UIImageView *cellImageProfileSnap = (UIImageView *)[cell viewWithTag:5];
[cellImageProfileSnap sd_setImageWithURL:[NSURL URLWithString:[_arrPictures objectAtIndex:indexPath.row]] placeholderImage:[UIImage imageNamed:#“…”]];
}
In viewDidLoad I initialize my NSOperationQueue (defined in my interface):
myQueue = [[NSOperationQueue alloc] init];
[myQueue setMaxConcurrentOperationCount:100];
[myQueue setName:#"com.sada"];
My goal is to make everything faster because the loading in tableView is slow and I think that is not dependent on SDWebImage. Please help me

slow loading using initWithContentsOfUrl

I have a web service and I make HTTP calls to it from cocoa using this line of code:
NSData *imageData = [[NSData alloc] initWithContentsOfUrl:url options: NSDataReadingUncached error:&error];
Sometimes is it take 10 seconds, sometimes 30 seconds to load the picture from this URL.
I tried loading this URL from a normal browser and it takes 1-2 seconds.
I'm doing lazy loading and the problem is the time it takes to load the contents of this URL vs a normal browser. Both tests were done from the same network.
Download.m
NSError *error;
NSData *imageData = [[NSData alloc] initWithContentsOfURL:self.photoRecord.URL options:NSDataReadingUncached error:&error];
NSMutableArray *jsonArray = [NSJSONSerialization JSONObjectWithData:imageData options:NSJSONReadingAllowFragments error:&myError];
NSMutableDictionary *pictureInfo = [jsonArray objectAtIndex:0];
NSString *picture;
picture = [pictureInfo valueForKey:#"Picture"];
NSData *base64Data = [[NSData alloc]initWithBase64Encoding:picture];
if (base64Data) {
UIImage *downloadedImage = [UIImage imageWithData:base64Data];
self.photoRecord.image = downloadedImage;
}
[(NSObject *)self.delegate performSelectorOnMainThread:#selector(imageDownloaderDidFinish:) withObject:self waitUntilDone:NO];
Then on the main thread PictureController.m:
-(void) loadScrollViewWithPage:(NSUInteger)page{
....
NSIndexPath *myIndexPath = [NSIndexPath indexPathForRow:page inSection:0];
[self startOperationsForPhotoRecord:aRecord atIndexPath:myIndexPath];
}
- (void)startOperationsForPhotoRecord:(PictureRecord *)record atIndexPath:(NSIndexPath *)indexPath {
Download *imageD = [[Download alloc] initWithPhotoRecord:record atIndexPath:indexPath delegate:self];
[self.pendingOperations.downloadsInProgress setObject:imageD forKey:indexPath];
[self.pendingOperations.downloadQueue addOperation:imageD];
}
Then I have the delegate method to update the UIImageView when the download is done which is working just fine.
The size of the content being loaded is around 400kb.
Any ideas?

xcode async tableview load image move listview images gone

We want to download image and data async to our tableview and we want to cache it not to download it again. We found a code for caching.Here is our code. It works asynchronously but when we scroll table view, images gone and come back(we cant see image for a while). Sometimes wrong image come to wrong cell. What might be the reasons and how can we solve it ?
NSURL *imageURL = [NSURL URLWithString:[NSString stringWithFormat:#"%#%#",[userInfo[0] serverUrl],[estateList[indexPath.row] imgUrl]]];
NSString *key = [imageURL absoluteString];
NSData *data = [FTWCache objectForKey:key];
if (data) {
UIImage *image = [UIImage imageWithData:data];
cell.imageView.image = image;
} else {
cell.imageView.image = [UIImage imageNamed:#"yukleniyor"];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^{
NSData *data = [NSData dataWithContentsOfURL:imageURL];
[FTWCache setObject:data forKey:key];
UIImage *image = [UIImage imageWithData:data];
dispatch_async(dispatch_get_main_queue(), ^{
cell.imageView.image = image;
});
});
}
Here is that code we found for caching
Header is like this
#import <Foundation/Foundation.h>
#interface FTWCache : NSObject
+ (void) resetCache;
+ (void) setObject:(NSData*)data forKey:(NSString*)key;
+ (id) objectForKey:(NSString*)key;
#end
And .m file is like this
#import "FTWCache.h"
static NSTimeInterval cacheTime = (double)604800;
#implementation FTWCache
+ (void) resetCache {
[[NSFileManager defaultManager] removeItemAtPath:[FTWCache cacheDirectory] error:nil];
}
+ (NSString*) cacheDirectory {
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cacheDirectory = [paths objectAtIndex:0];
cacheDirectory = [cacheDirectory stringByAppendingPathComponent:#"FTWCaches"];
return cacheDirectory;
}
+ (NSData*) objectForKey:(NSString*)key {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *filename = [self.cacheDirectory stringByAppendingPathComponent:key];
if ([fileManager fileExistsAtPath:filename])
{
NSDate *modificationDate = [[fileManager attributesOfItemAtPath:filename error:nil] objectForKey:NSFileModificationDate];
if ([modificationDate timeIntervalSinceNow] > cacheTime) {
[fileManager removeItemAtPath:filename error:nil];
} else {
NSData *data = [NSData dataWithContentsOfFile:filename];
return data;
}
}
return nil;
}
+ (void) setObject:(NSData*)data forKey:(NSString*)key {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *filename = [self.cacheDirectory stringByAppendingPathComponent:key];
BOOL isDir = YES;
if (![fileManager fileExistsAtPath:self.cacheDirectory isDirectory:&isDir]) {
[fileManager createDirectoryAtPath:self.cacheDirectory withIntermediateDirectories:NO attributes:nil error:nil];
}
NSError *error;
#try {
[data writeToFile:filename options:NSDataWritingAtomic error:&error];
}
#catch (NSException * e) {
//TODO: error handling maybe
}
}
#end
Sorry for my previous answer.
I will try to explain the problem:
We have TableView total number of rows and rows of the reserved area of the display. As a result, images with asynchronous load can not be loaded into their cells (because it is inserted as it downloads from the memory).
The solution is very simple, you must assign each ImageView with key and this key associated with the cells of the table.
I resolve this problem by using code from this git (https://gist.github.com/khanlou/4998479)
There are two files on it
UIImageView+Network.h
UIImageView+Network.m
You must include they in your project, or create own class and paste to it.
This class uses FTW/FTWCache from (https://github.com/FTW/FTWCache/tree/master/FTWCache). So you must add to your project this one too.
After that you must to import
#import "UIImageView+Network.h"
in file which will use asynchronous image loading and caching.
And short part of code with TableView using
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"MyTableCell";
MyTableCell *cell = (MyTableCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil){
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"MyTableCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
// construction to call method
// [cell.imageView loadImageFromURL:(NSURL*)url placeholderImage:(UIImage*)placeholder cachingKey:(NSString*)key ];
[cell.thumbnailImageView loadImageFromURL:(NSURL*)url placeholderImage:[UIImage imageNamed:#"no_foto.gif"] cachingKey:(NSString*)[NSString stringWithFormat:#"%d",indexPath.row]];
return cell;
}

fetch image by using url

I want image on view by fetching it from some url. I want changing in given code..
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
UIImage *image = [[UIImage imageNamed:<#(NSString *)name#>
NSString * mediaUrl = [[[self appDelegate]currentlySelectedBlogItem]mediaUrl];
[[self image]setImage:[UIImage imageNamed:#"unknown.jpg"]];
if(nil != mediaUrl){
NSData* imageData;
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
#try {
imageData = [[NSData alloc]initWithContentsOfURL:[NSURL URLWithString:mediaUrl]];
}
#catch (NSException * e) {
//Some error while downloading data
}
#finally {
UIImage * imageFromImageData = [[UIImage alloc] initWithData:imageData];
[[self image]setImage:imageFromImageData];
[imageData release];
[imageFromImageData release];
}
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}
self.titleTextView.text = [[[self appDelegate] currentlySelectedBlogItem]title];
self.descriptionTextView.text = [[[self appDelegate] currentlySelectedBlogItem]description];
}
Using this will give you a solution
NSURL *url = [NSURL URLWithString:#"ENTER YOUR URL HAVING THE IMAGE"];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:data];
I have used the following:
NSString *url=[NSString stringWithFormat:#"Your URL"];
//NSLog(#"URL=%#",url);
UIImage *myImage=[[UIImage alloc] initWithData:[NSData UIImage *myImage=[[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString: url]]];
NSLog(#"%d byte of data", [[NSData dataWithContentsOfURL: [NSURL URLWithString: url]] length]);
if (myImage)
{
//THIS CODE WILL STORE IMAGE DOCUMENT DIRECTORY
NSString *jpegFilePath = [NSString stringWithFormat:#"%#/%#.jpg",[self pathForDocumentDirectory],[self.idOfImagesToDownload objectAtIndex:i]];
NSData *data1 = [NSData dataWithData:UIImageJPEGRepresentation(myImage, 1.0f)];//1.0f = 100% quality
[data1 writeToFile:jpegFilePath atomically:YES];
}
NOTE:[self pathForDocumentDirectory] is method returning path of document directory.