insert images to the device's cache - iOS - iphone

is there a way to insert images, that are downloaded from the web, to the devices cache?
in my application, there's a few views that contains images. at every tableView there's 25-30 images.
the problem is that the images are loaded when scrolled, and the result is at scrolling the image takes 2-3 seconds to reload... doesn't look good :)
at the moment, i'm using NSURLRequest at each cell.
NSURL* url = [NSURL URLWithString:article.articleImage];
NSURLRequest* request = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse * response,
NSData * data,
NSError * error)
{
if (!error)
{
UIImage* image = [[UIImage alloc] initWithData:data];
MainImg.image = image;
article.articleImg=image;
}
}];
I've tried to use multi thread, but the launch of the application takes too long.
ideas?

Hi you need UIImageView+AFNetworking.h category download and use AFNetworking u are sorted
use its - (void)setImageWithURL:(NSURL *)url method works like charm

You can use NSURLCache for this purpose. Yesterday I've worked with this, and I make class:
#interface MyURLCache : NSURLCache
#property (nonatomic, assign) NSTimeInterval timeAvaiable;
#end
#implementation MyURLCache
- (id)initWithMemoryCapacity:(NSUInteger)memoryCapacity diskCapacity:(NSUInteger)diskCapacity diskPath:(NSString *)path
{
self = [super initWithMemoryCapacity:memoryCapacity diskCapacity:diskCapacity diskPath:path];
if(self){
_timeAvaiable = 5*60;//5 мин
}
return self;
}
- (id)init
{
self = [super init];
if(self){
_timeAvaiable = 5*60;
}
return self;
}
+ (NSCachedURLResponse*)addInfoDataToCachedResponce:(NSCachedURLResponse*)cachedResponse
{
NSMutableDictionary* newUserInfo = [#{#"LastUpdate" : #([[NSDate date] timeIntervalSince1970])} mutableCopy];
if([cachedResponse userInfo])
newUserInfo[#"UserInfo"] = [cachedResponse userInfo];
return [[NSCachedURLResponse alloc] initWithResponse:[cachedResponse response]
data:[cachedResponse data]
userInfo:newUserInfo
storagePolicy:[cachedResponse storagePolicy]];
}
+ (NSCachedURLResponse*)removeInfoDataFromCachedResponce:(NSCachedURLResponse*)cachedResponse
{
return [[NSCachedURLResponse alloc] initWithResponse:[cachedResponse response]
data:[cachedResponse data]
userInfo:[cachedResponse userInfo][#"UserInfo"]
storagePolicy:[cachedResponse storagePolicy]];
}
- (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request
{
NSCachedURLResponse* result = [super cachedResponseForRequest:request];
NSDate* lastUpdate = [NSDate dateWithTimeIntervalSince1970:[result.userInfo[#"LastUpdate"] doubleValue]];
BOOL expired = fabs([lastUpdate timeIntervalSinceNow]) > _timeAvaiable;
return expired? nil : [[self class] removeInfoDataFromCachedResponce:result];
}
- (void)storeCachedResponse:(NSCachedURLResponse *)cachedResponse forRequest:(NSURLRequest *)request
{
[super storeCachedResponse:[[self class] addInfoDataToCachedResponce:cachedResponse] forRequest:request];
}
#end
And just enable cache when app loaded:
MyURLCache *URLCache = [[MyURLCache alloc] initWithMemoryCapacity:4 * 1024 * 1024
diskCapacity:20 * 1024 * 1024
diskPath:[SDURLCache defaultCachePath]];
[NSURLCache setSharedURLCache:URLCache];
For each request need set cachePolicy to NSURLRequestReturnCacheDataElseLoad.
Or just use AFNetworking :)
- (void)setImageWithURLRequest:(NSURLRequest *)urlRequest
placeholderImage:(UIImage *)placeholderImage
success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image))success
failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error))failure;

In all my apps I'm using this framework. Very simple to use
https://github.com/rs/SDWebImage
Code example
[cell.imageView setImageWithURL:[NSURL URLWithString:#"http://www.domain.com/path/to/image.jpg"]
placeholderImage:[UIImage imageNamed:#"placeholder.png"]
];

Use This:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory,NSUserDomainMask, YES);
NSString *savedImagePath = [NSString stringWithFormat:#"%#/%#",[paths objectAtIndex:0],[article.articleImage lastPathComponent]];
UIImage *image = [UIImage imageNamed:savedImagePath];
if(!image)
{
NSURL* url = [NSURL URLWithString:article.articleImage];
NSURLRequest* request = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse * response,
NSData * data,
NSError * error)
{
if (!error)
{
[data writeToFile:savedImagePath atomically:NO];
UIImage* image = [UIImage imageNamed:savedImagePath];
MainImg.image = image;
article.articleImg=image;
}
}];
}
else
{
MainImg.image = image;
article.articleImg=image;
}

Related

Calls to NSURLConnectionDataDelegate methods to download images only works occasionally

I currently have two UIImageViews in my storyboard, one of which downloads my own Facebook profile picture, and the other a friend's profile picture.
However, my issue is that only 60% of the time this works as expected, while the other 40% of the times my own profile picture appears where my friend's picture should show in the bottom, while the top box remains empty. I am unsure whether this is the result of how I call the NSURLConnectionDataDelegate methods as it downloads or completes view, or the nature of my requests called to Facebook.
I've pasted the condensed version of my two requests to Facebook in viewDidLoad, one which gets my own profile pic, and the other to get my friend's pic:
// ----- Gets my own profile picture, using requestForMe -----
FBRequest *request = [FBRequest requestForMe];
[request startWithCompletionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
//handle response
if(!error){
//Some methods not included for breveity, includes facebookID used below
NSURL *pictureURL = [NSURL URLWithString:[NSString stringWithFormat:#"https://graph.facebook.com/%#/picture?type=large&return_ssl_resources=1", facebookID]];
self.imageData = [[NSMutableData alloc] init];
switcher = 1;
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:pictureURL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:2.0f];
NSURLConnection *urlConnection = [[NSURLConnection alloc] initWithRequest:urlRequest delegate:self];
if (!urlConnection){
NSLog(#"Failed to download picture");
}
}
}];
// ----- Gets a profile picture of my friend, using requestForMyFriends -----
FBRequest *requestForFriends = [FBRequest requestForMyFriends];
[requestForFriends startWithCompletionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
if(!error){
//Other methods not included, including facebookFriendID
NSURL *friendPictureURL = [NSURL URLWithString:[NSString stringWithFormat:#"https://graph.facebook.com/%#/picture?type=large&return_ssl_resources=1", facebookFriendID]];
self.supportImageData = [[NSMutableData alloc] init];
switcher = 2;
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:friendPictureURL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:2.0f];
NSURLConnection *urlConnection = [[NSURLConnection alloc] initWithRequest:urlRequest delegate:self];
if (!urlConnection){
NSLog(#"Failed to download picture");
}
}
}];
Both requests make calls to the NSURLConnectionDataDelegate methods, and I use the switcher to decide when to load which picture:
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
// As chuncks of the image are received, we build our data file
if (switcher == 1) [self.imageData appendData:data];
if (switcher == 2)[self.supportImageData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
//When the entire image is finished downloading
if (switcher == 1) {
UIImage *image = [UIImage imageWithData:self.imageData]; //puts the completed picture into the UI
self.titleImageView.image = image;
[self.titleImageView setClipsToBounds:YES];
}
if (switcher == 2) {
UIImage *supportImage = [UIImage imageWithData:self.supportImageData];
self.supportImageView.image = supportImage;
[self.titleImageView setClipsToBounds:YES];
}
}
You have two asynchronous processes, both of which can result in having your NSURLConnectionDataDelegate methods in self being called. But if they happen at the same time, they're going to step on top of each other (you're presumably using a single NSMutableData variable to reference the data being downloaded).
Either create dedicated class that you can instantiate once for each of your two NSURLConnection requests (a NSOperation based approach, like AFNetworking, is ideal), or use sendAsynchronousRequest instead. But don't use a single object as the delegate for two concurrent NSURLConnection requests at the same time.
If you wanted to see a minimalist download operation, it might look like:
// NetworkOperation.h
#import <Foundation/Foundation.h>
typedef void(^DownloadCompletion)(NSData *data, NSError *error);
#interface NetworkOperation : NSOperation
- (id)initWithURL:(NSURL *)url completion:(DownloadCompletion)completionBlock;
#property (nonatomic, copy) NSURL *url;
#property (nonatomic, copy) DownloadCompletion downloadCompletionBlock;
#end
and
// NetworkOperation.m
#import "NetworkOperation.h"
#interface NetworkOperation () <NSURLConnectionDataDelegate>
#property (nonatomic, readwrite, getter = isExecuting) BOOL executing;
#property (nonatomic, readwrite, getter = isFinished) BOOL finished;
#property (nonatomic, strong) NSMutableData *data;
#end
#implementation NetworkOperation
#synthesize finished = _finished;
#synthesize executing = _executing;
- (id)initWithURL:(NSURL *)url completion:(DownloadCompletion)downloadCompletionBlock
{
self = [super init];
if (self) {
self.url = url;
self.downloadCompletionBlock = downloadCompletionBlock;
_executing = NO;
_finished = NO;
}
return self;
}
#pragma mark - NSOperation related stuff
- (void)start
{
if ([self isCancelled]) {
self.finished = YES;
return;
}
self.executing = YES;
NSURLRequest *request = [NSURLRequest requestWithURL:self.url];
NSAssert(request, #"%s: requestWithURL failed for URL '%#'", __FUNCTION__, [self.url absoluteString]);
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
[connection scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
[connection start];
}
- (void)setExecuting:(BOOL)executing
{
[self willChangeValueForKey:#"isExecuting"];
_executing = executing;
[self didChangeValueForKey:#"isExecuting"];
}
- (void)setFinished:(BOOL)finished
{
[self willChangeValueForKey:#"isFinished"];
_finished = finished;
[self didChangeValueForKey:#"isFinished"];
}
- (BOOL)isConcurrent
{
return YES;
}
#pragma mark NSURLConnectionDataDelegate methods
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
self.data = [NSMutableData data];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
if ([self isCancelled]) {
[connection cancel];
self.executing = NO;
self.finished = YES;
return;
}
[self.data appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
if (self.downloadCompletionBlock) {
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
self.downloadCompletionBlock(self.data, nil);
self.downloadCompletionBlock = nil;
}];
}
self.executing = NO;
self.finished = YES;
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
if (self.downloadCompletionBlock) {
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
self.downloadCompletionBlock(nil, error);
self.downloadCompletionBlock = nil;
}];
}
self.executing = NO;
self.finished = YES;
}
#end
And then, when you wanted to use it, it might look like:
NSOperationQueue *networkQueue = [[NSOperationQueue alloc] init];
queue.maxConcurrentOperationCount = 4;
// ----- Gets my own profile picture, using requestForMe -----
FBRequest *request = [FBRequest requestForMe];
[request startWithCompletionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
//handle response
if(!error) {
//Some methods not included for breveity, includes facebookID used below
NSURL *pictureURL = [NSURL URLWithString:[NSString stringWithFormat:#"https://graph.facebook.com/%#/picture?type=large&return_ssl_resources=1", facebookID]];
[networkQueue addOperation:[[NetworkOperation alloc] requestWithURL:pictureURL completion:^(NSData *data, NSError *error) {
if (!error) {
self.meImageView.image = [UIImage imageWithData:data];
}
}]];
}
}];
// ----- Gets a profile picture of my friend, using requestForMyFriends -----
FBRequest *requestForFriends = [FBRequest requestForMyFriends];
[requestForFriends startWithCompletionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
if(!error){
//Other methods not included, including facebookFriendID
NSURL *friendPictureURL = [NSURL URLWithString:[NSString stringWithFormat:#"https://graph.facebook.com/%#/picture?type=large&return_ssl_resources=1", facebookFriendID]];
[networkQueue addOperation:[[NetworkOperation alloc] requestWithURL:friendPictureURL completion:^(NSData *data, NSError *error) {
if (!error) {
self.friendImageView.image = [UIImage imageWithData:data];
}
}]];
}
}];

How to fetch xml image and show in UIcollectionview ? (change code for Json to XML)

I'm a newbie xcode programmer.
I've read a tutorial for showing collectionview using Flickr Json.
here is the two links: http://www.raywenderlich.com/22324/beginning-uicollectionview-in-ios-6-part-12
and
http://www.raywenderlich.com/22417/beginning-uicollectionview-in-ios-6-part-22
but now I want to make the collectionview for Danbooru, a site which only shows XML.
the tutorial above uses 4 author-made files, (Flickr.h, Flickr.m, FlickrPhoto.h, FlickrPhoto.m)
I think Flickr.m file does the key part in that app, so will quote that code:
#import "Flickr.h"
#import "FlickrPhoto.h"
#define kFlickrAPIKey #"d02c877c0a4220890f14fc95f8b16983"
#implementation Flickr
+ (NSString *)flickrSearchURLForSearchTerm:(NSString *) searchTerm
{
searchTerm = [searchTerm stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
return [NSString stringWithFormat:#"http://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=%#&text=%#&per_page=20&format=json&nojsoncallback=1",kFlickrAPIKey,searchTerm];
}
+ (NSString *)flickrPhotoURLForFlickrPhoto:(FlickrPhoto *) flickrPhoto size:(NSString *) size
{
if(!size)
{
size = #"m";
}
return [NSString stringWithFormat:#"http://farm%d.staticflickr.com/%d/%lld_%#_%#.jpg",flickrPhoto.farm,flickrPhoto.server,flickrPhoto.photoID,flickrPhoto.secret,size];
}
- (void)searchFlickrForTerm:(NSString *) term completionBlock:(FlickrSearchCompletionBlock) completionBlock
{
NSString *searchURL = [Flickr flickrSearchURLForSearchTerm:term];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
NSError *error = nil;
NSString *searchResultString = [NSString stringWithContentsOfURL:[NSURL URLWithString:searchURL]
encoding:NSUTF8StringEncoding
error:&error];
if (error != nil) {
completionBlock(term,nil,error);
}
else
{
// Parse the JSON Response
NSData *jsonData = [searchResultString dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *searchResultsDict = [NSJSONSerialization JSONObjectWithData:jsonData
options:kNilOptions
error:&error];
if(error != nil)
{
completionBlock(term,nil,error);
}
else
{
NSString * status = searchResultsDict[#"stat"];
if ([status isEqualToString:#"fail"]) {
NSError * error = [[NSError alloc] initWithDomain:#"FlickrSearch" code:0 userInfo:#{NSLocalizedFailureReasonErrorKey: searchResultsDict[#"message"]}];
completionBlock(term, nil, error);
} else {
NSArray *objPhotos = searchResultsDict[#"photos"][#"photo"];
NSMutableArray *flickrPhotos = [#[] mutableCopy];
for(NSMutableDictionary *objPhoto in objPhotos)
{
FlickrPhoto *photo = [[FlickrPhoto alloc] init];
photo.farm = [objPhoto[#"farm"] intValue];
photo.server = [objPhoto[#"server"] intValue];
photo.secret = objPhoto[#"secret"];
photo.photoID = [objPhoto[#"id"] longLongValue];
NSString *searchURL = [Flickr flickrPhotoURLForFlickrPhoto:photo size:#"m"];
NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:searchURL]
options:0
error:&error];
UIImage *image = [UIImage imageWithData:imageData];
photo.thumbnail = image;
[flickrPhotos addObject:photo];
}
completionBlock(term,flickrPhotos,nil);
}
}
}
});
}
+ (void)loadImageForPhoto:(FlickrPhoto *)flickrPhoto thumbnail:(BOOL)thumbnail completionBlock:(FlickrPhotoCompletionBlock) completionBlock
{
NSString *size = thumbnail ? #"m" : #"b";
NSString *searchURL = [Flickr flickrPhotoURLForFlickrPhoto:flickrPhoto size:size];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
NSError *error = nil;
NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:searchURL]
options:0
error:&error];
if(error)
{
completionBlock(nil,error);
}
else
{
UIImage *image = [UIImage imageWithData:imageData];
if([size isEqualToString:#"m"])
{
flickrPhoto.thumbnail = image;
}
else
{
flickrPhoto.largeImage = image;
}
completionBlock(image,nil);
}
});
}
#end
so that was the code for Json,
and by searching, I found a way to parse XML with TBXML(opensource)
by implementing the code below in viewController on another testproject, I could see URL of image coming out on debug screen:
void (^tbxmlSuccessBlock)(TBXML *) = ^(TBXML * tbxml){
TBXMLElement *elemRoot = nil, *elemImage = nil ;
elemRoot = tbxml.rootXMLElement;
if(elemRoot){
elemImage = [TBXML childElementNamed:#"post" parentElement:elemRoot];
while(elemImage){{
NSString *localURL = [TBXML valueOfAttributeNamed:#"file_url" forElement:elemImage];
NSLog(#"Local : %#", localURL);
NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:localURL]];
UIImage *image = [UIImage imageWithData:imageData];
weatherPhoto.largeImage = image;
elemImage=elemImage->nextSibling;
}}
}};
void (^tbxmlFailureBlock) (TBXML *, NSError *) = ^(TBXML * tbxml, NSError * error){
NSLog(#"Error: %#", error);
};
- (void)parseXML{
NSURL *imageURL = [NSURL URLWithString:#"http://safebooru.org/index.php?page=dapi&s=post&q=index&limit=5"];
[TBXML newTBXMLWithURL:imageURL success:tbxmlSuccessBlock failure:tbxmlFailureBlock];}
- (void)viewDidLoad
{
[super viewDidLoad];
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
[NSThread detachNewThreadSelector:#selector(parseXML) toTarget:self withObject:nil];
}
so far this is all what I got.getting URL text.
How can I change the Flickr.m and make image from XML to be shown in UIcollectionView?
So I read your question again, and realized you asked something else. Are you asking how to make Flickr.m load an image from the XML? you don't. This class is meant to load flickr photos. You need to write your own class, that knows how to extract the url from the XML and load the image using the example I gave you.
You need to create a UIImage instance and load it asynchronously.
For example:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
NSData * imageData = [NSData dataWithContentsOfURL:self.URL];
self.image = [UIImage imageWithData:imageData];
dispatch_async(dispatch_get_main_queue(), ^{
if (self.image)
[self setupImageView];
});
You can also use NSOperationQueue or NSURLConnection to perform async data loading.

iPhone - NSURLConnection asynchronous download using URLs in NSArray

I have seen almost all the posts about NSURL on this site, and I am still stuck. I am using Xcode 4.5.
I am trying to download images and display them in a UIScrollView.
I want to download asynchronously download images using URLs, that get stored in an array populated using JSON. I get the URLs from a JSON grab off of my database. That works quite well and I can see the URL's being placed into the urlArray, but making the URLConnection to get the image, seems to fail.
I can't get any of the images to download, or at least they don't show up in my imageArray.
Here is my code and thank you for any help!! Let me know what else is needed
- (void)viewDidLoad
{
[super viewDidLoad];
//show network activity to user.... very useful
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
//call getJSON. getJSON does not parse, but it connects and gets the data.
[self getJSON];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)getJSON
{
NSURL *url = [NSURL URLWithString:#"http://"My server goes here/json.php"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
//just initialize the connection, do not
[[NSURLConnection alloc] initWithRequest:request delegate:self]; //"Ecression result unused" warning here
}
- (void)getNextImage
{
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
for (int y = 0; y < urlArray.count; y++)
{
NSString *urlString = [urlArray objectAtIndex:y];
NSLog(#"Array String is: %# ", urlString);
NSURL *arrayURL = [NSURL URLWithString:urlString];
NSURLRequest *imageRequest = [NSURLRequest requestWithURL:arrayURL];
NSData *imgData = [[NSURLConnection alloc] initWithRequest:imageRequest delegate:self]; //"Incompatible pointer types initializing ..." warning here
imageData = [UIImage imageWithData:imgData];
[imageArray addObject:imageData];
}
NSLog(#"LEAVING getNextImage");
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
theJsonData = [[NSMutableData alloc] init];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[theJsonData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
urlArray = [[NSMutableArray alloc] init];
//This is where all the JSON Parsing is being done.
//Turn off the data indicator, because the download is complete.
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
jsonArray = [NSJSONSerialization JSONObjectWithData:theJsonData options:nil error:nil]; //"Incompatible pointer types initializing ..." warning here
//get the URL strings out of the jsonArray
for (int x = 0; x < jsonArray.count; x++)
{
NSString *urlString = [[jsonArray objectAtIndex:x] objectForKey:#"image_URL"];
NSLog(#"String is %# ", urlString);
[urlArray addObject:urlString];
}
[self getNextImage];
//display the images..... Not sure why this is in connectionDidFinishLoading.
for (int x = 0; x < imageArray.count; x++)
{
CGRect frame;
frame.origin.x = self.mainScroll.frame.size.width * x;
frame.origin.y = 0;
frame.size = self.mainScroll.frame.size;
UIImageView *nextIV = [[UIImageView alloc] initWithFrame:frame];
[nextIV setImage:imageData];
[self.mainScroll addSubview:nextIV];
//NSLog(#"Pass %d", x);
}
self.mainScroll.contentSize = CGSizeMake(self.mainScroll.frame.size.width * imageArray.count,1.0);
NSLog(#"!!!!!!leaving connection did finnish loading!!!!!");
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
//show error message to user if there is a connection error.
UIAlertView *errorView = [[UIAlertView alloc] initWithTitle:#"Error" message:#"The Download could not complete - please make sure you're connected to the internet." delegate:nil cancelButtonTitle:#"Dismiss" otherButtonTitles:nil];
[errorView show];
//turn off the network activity indicatior
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}
you never download imageData. you assign it the request object . thats why you get the warning too. a NSURLConnection object is not a NSData object: NSData *imgData = [[NSURLConnection alloc] initWithRequest:imageRequest delegate:self]; //"Incompatible pointer types initializing ..." warning here
I would today rewrite it using the startAsyncConnection method. sec
-- there you go, untested and written in text edit but it should get you started (I reused most of your code but cut it down a lot too)
#import "RootViewController.h"
#interface RootViewController ()
#property(assign) IBOutlet UIScrollView *mainScroll;
#end
#implementation RootViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
[self getJSONAndImageData];
}
- (void)getJSONAndImageData
{
NSURL *url = [NSURL URLWithString:#"http://My server goes here/json.php"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse*r, NSData*d, NSError*e) {
[self parseJSONAndGetImages:d];
}];
}
- (void)parseJSONAndGetImages:(NSData*)data
{
NSMutableArray *urlArray = [[NSMutableArray alloc] init];
//This is where all the JSON Parsing is being done.
//Turn off the data indicator, because the download is complete.
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
NSArray *jsonArray = (NSArray*)[NSJSONSerialization JSONObjectWithData:data options:nil error:nil]; //"Incompatible pointer types initializing ..." warning here => likely not an array then
assert([jsonArray isKindOfClass:[NSArray class]]);
//could be made in one liner with KVC
//get the URL strings out of the jsonArray
for (int x = 0; x < jsonArray.count; x++)
{
NSString *urlString = [[jsonArray objectAtIndex:x] objectForKey:#"image_URL"];
NSLog(#"String is %# ", urlString);
[urlArray addObject:urlString];
}
[self loadImageArray:urlArray handler:^(NSArray* imageArray) {
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
for (int x = 0; x < imageArray.count; x++)
{
CGRect frame;
frame.origin.x = self.mainScroll.frame.size.width * x;
frame.origin.y = 0;
frame.size = self.mainScroll.frame.size;
UIImageView *nextIV = [[UIImageView alloc] initWithFrame:frame];
[nextIV setImage:imageArray[x]];
[self.mainScroll addSubview:nextIV];
//NSLog(#"Pass %d", x);
}
self.mainScroll.contentSize = CGSizeMake(self.mainScroll.frame.size.width * imageArray.count,1.0);
}];
}
//for SIMPLICITY I do synchronous networking here!
- (void)loadImageArray:(NSArray *)urlArray handler:(void(^)())handler {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSMutableArray *imageArray = [NSMutableArray array];
for (int y = 0; y < urlArray.count; y++)
{
NSString *urlString = [urlArray objectAtIndex:y];
NSLog(#"Array String is: %# ", urlString);
NSURL *arrayURL = [NSURL URLWithString:urlString];
NSURLRequest *imageRequest = [NSURLRequest requestWithURL:arrayURL];
NSData *imgData = [NSURLConnection sendSynchronousRequest:imageRequest returningResponse:nil error:nil];
UIImage *image = [UIImage imageWithData:imgData];
[imageArray addObject:image];
}
dispatch_async(dispatch_get_main_queue(),^ {
handler(imageArray);
});
});
}
#end

Trouble using a custom NSObject class to simplify repetitive code in iPhone app

I am trying to store a REST connection model in a single object so that I don't keep having to use it over and over again. Here is the model I created:
//RestModel.h
#import "ASIHTTPRequest.h"
#interface RestModel : NSObject{
NSString* _baseUrl;
NSString* _modelUrl;
}
#property (nonatomic, retain) NSString* modelUrl;
- (id)initWithModel:(NSString*)model;
- (NSDictionary*)getById:(NSInteger*)ident;
- (NSDictionary*)getAll;
#end
//RestModel.m
#import "RestModel.h"
#implementation RestModel
#synthesize modelUrl = _modelUrl;
- (id)init
{
self = [super init];
if (self) {
_baseUrl = #"http://myRESTurl.com";
}
return self;
}
- (id)initWithModel:(NSString*)model
{
self = [super init];
if (self) {
_baseUrl = #"http://myRESTurl.com";
self.modelUrl = [NSString stringWithFormat:#"%#/%#/", _baseUrl, model];
}
return self;
}
- (NSDictionary*)HTTPRequest:(NSURL*)url
{
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request startSynchronous];
NSError *error = [request error];
if(!error){
NSData *responseData = [request responseData];
NSString *errorDesc = nil;
NSPropertyListFormat format;
[error release];
[request release];
return (NSDictionary*)[NSPropertyListSerialization propertyListFromData:responseData mutabilityOption:NSPropertyListMutableContainersAndLeaves format:&format errorDescription:&errorDesc];
}else{
NSLog(#"%#", error);
return nil;
}
}
- (NSDictionary*)getById:(NSInteger*)ident
{
NSURL* url = [NSURL URLWithString:[NSString stringWithFormat:#"%#/%#", self.modelUrl, ident]];
return [self HTTPRequest:url];
}
- (NSDictionary*)getAll
{
NSURL* url = [NSURL URLWithString:[NSString stringWithFormat:#"%#", self.modelUrl]];
return [self HTTPRequest:url];
}
- (void)dealloc
{
[_modelUrl release];
// [_responseData release];
// [_responseDict release];
[super dealloc];
}
#end
Edit: Now it isn't crashing, but my local NSDictionary has a count of 0. I'm calling the following in -viewDidLoad in my controller:
RestModel* rm = [[RestModel alloc] initWithModel:#"user"];
self.dict = [rm getAll];
[rm release];
I planted NSLog of [self.dict count] throughout the controller. It is always 0. The RestModel rm is called, the functions are called (again more NSLogs), but no data. Any ideas?
[error release];
[request release];
Those should be auto-released objects, as you got them by convenience methods, so releasing them explicitly will make your application crash.
NSInteger isn't an object so it isn't necessary to pass it using NSInteger * and certainly you do not want to use the %# format specifier. Instead try this:
- (NSDictionary*)getById:(NSInteger)ident
{
NSURL* url = [NSURL URLWithString:[NSString stringWithFormat:#"%#/%d", self.modelUrl, ident]];
return [self HTTPRequest:url];
}

Displaying an Image from URL Objective C

Is there any way of achieving the following that avoids using "initWithData" ? (Just in case you are curious, initWithData is getting my app flagged by Apple as using an illegal API sigh).
NSData * imageData = [NSData dataWithContentsOfURL : [NSURL URLWithString : [details image]]];
picture = [[UIImage alloc] initWithData:imageData];
Many thanks,
Martin
if you want to get the image data,then initialize a UIImage using that data:
NSData * imageData = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString: #"http://Serverurl/pic007.jpg"]];
cell.image = [UIImage imageWithData: imageData];
[imageData release];
First of all, you should do this asynchronously so that your thread won't block. Here is the code for the class:
#implementation AsyncImageView
+ (void)initialize {
[NSURLCache setSharedURLCache:[[SDURLCache alloc] initWithMemoryCapacity:0
diskCapacity:10*1024*1024
diskPath:[SDURLCache defaultCachePath]]];
}
- (void)setImageFromURL:(NSURL *)url{
/* Put activity indicator */
if(!activityIndicator) {
activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
CGRect frame = [activityIndicator frame];
frame.origin.x = (self.frame.size.width - frame.size.width)/2;
frame.origin.y = (self.frame.size.height - frame.size.height)/2;
activityIndicator.tag = 9999;
activityIndicator.frame = frame;
[self addSubview:activityIndicator];
[activityIndicator startAnimating];
}
/* Cancel previous request */
if(fetchImageConnection) {
[fetchImageConnection cancel];
}
[imageData release];
/* Start new request */
NSURLRequest *req = [NSURLRequest requestWithURL:url
cachePolicy:NSURLRequestReturnCacheDataElseLoad
timeoutInterval:30];
imageData = [NSMutableData new];
fetchImageConnection = [NSURLConnection connectionWithRequest:req
delegate:self];
[fetchImageConnection retain];
}
- (void)setImageFromDisk:(UIImage *)img {
self.image = img;
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[imageData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
if(connection == fetchImageConnection) {
self.image = [UIImage imageWithData:imageData];
[[NSNotificationCenter defaultCenter] postNotificationName:#"imageDownloaded" object:self];
[activityIndicator removeFromSuperview];
[imageData release];
[activityIndicator release];
activityIndicator = nil;
imageData = nil;
fetchImageConnection = nil;
}
[connection release];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
[connection release];
NSLog(#"error: %#", error);
}
#end
Try this code:
NSString *imgString = #"https://www.lockated.com/system/attachfiles/documents/000/002/489/original/ZPMHaJUSjAGnUrVuOmbqoExRMryvcySVOIkJQMivnAntvpmpYd.jpg?1501833649";
NSData *imageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:imgString]];
accountImageView.image = [UIImage imageWithData: imageData]; // accountImageView is imageView
NSData *receivedData = [NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://Serverurl/pic007.jpg"]];
self.image=nil;
UIImage *img = [[UIImage alloc] initWithData:receivedData ];
self.image = img;
[img release];
I hope this code will help you!!