I am having some really strange problems with NSURLConnection so I hope you can help me out.
What I am trying to do is download some data from a given URL using NSURLConnection.
I made my own helper class which receives data path, downloads it, and notifies the caller via delegate when the download completes.
The thing works perfectly on my iPhone with iOS 4.3. However, when tested on iOS 5 or iOS6, the connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
method is never called and I do not get the desired result.
The class .h file contains:
#import <Foundation/Foundation.h>
@protocol NIAsyncDownloaderDelegate
@required
- (void) asyncDownloaderDataDownloadComplete:(NSData *)data withError:(bool) error;
@end
@interface NIAsyncImageDownloader : NSObject <NSURLConnectionDataDelegate>
{
NSURLConnection *theConnection;
NSMutableData* myData;
NSURL *downloadURL;
id delegate;
}
-(id) initWithDataDownloadString:(NSString *) stringAddress;
@property (nonatomic, retain) id delegate;
@end
And the .m file looks like this:
#import "NIAsyncDownloader.h"
@implementation NIAsyncImageDownloader
@synthesize delegate;
-(id) initWithDataDownloadString:(NSString *)stringAddress
{
if (self = [super init])
{
[self loadDataFromURL:[NSURL URLWithString:stringAddress]];
}
return self;
}
- (void)loadDataFromURL:(NSURL*)url
{
NSLog(@"Called: %@", NSStringFromSelector(_cmd));
downloadURL = url;
NSURLRequest* request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
theConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
}
-(void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
NSLog(@"Called: %@", NSStringFromSelector(_cmd));
NSLog(@"The response is: %@, status code %i, url %@", response.description, ((NSHTTPURLResponse*)response).statusCode, ((NSHTTPURLResponse*)response).URL.description);
}
-(void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
NSLog(@"Called: %@", NSStringFromSelector(_cmd));
if (myData == nil)
{
myData = [[NSMutableData alloc] initWithCapacity:2048];
}
[myData appendData:data];
}
//CALLED ON iOS 4.3
- (void)connectionDidFinishLoading:(NSURLConnection*)connection
{
//so self data now has the complete image
NSLog(@"Called: %@", NSStringFromSelector(_cmd));
[self handleDownloadSuccess];
}
//CALLED ON iOS 5, iOS 6
-(void) connectionDidFinishDownloading:(NSURLConnection *)connection destinationURL:(NSURL *)destinationURL
{
NSLog(@"Called: %@", NSStringFromSelector(_cmd));
[self handleDownloadSuccess];
}
-(void) handleDownloadSuccess
{
NSLog(@"Called: %@", NSStringFromSelector(_cmd));
[theConnection release];
theConnection = nil;
[delegate asyncDownloaderDataDownloadComplete:myData withError:NO];
[myData release];
myData = nil;
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(@"Called: %@", NSStringFromSelector(_cmd));
[delegate asyncDownloaderDataDownloadComplete:nil withError:YES];
}
@end
Here are some screenshots to show you what I am talking about:
This is what happens when I run the application on iOS5 or iOS6, the request initializes itself, receives a response, and calls connectionDidFinishDownloading:(NSURLConnection *)connection destinationURL:(NSURL *)destinationURL
right away
However, when I run the same application on iOS 4.3, everything works perfectly as you can see from the screenshots below:
I also noticed that iOS 5 and iOS 6 do not call the same 'finish' method like the iOS 4.3, but I don't think that has has anything to do with my current issue.
And as a final thing, the documentation over here says that the method in question (connection:didReceiveData) is actually deprecated as of iOS 4.3: http://developer.apple.com/library/ios/#documentation/Foundation/Reference/NSURLConnectionDelegate_Protocol/DeprecationAppendix/AppendixADeprecatedAPI.html
However, another reference states that it is a part of NSURLConnectionDataDelegate protocol and is available since iOS 2: http://developer.apple.com/library/ios/#documentation/Foundation/Reference/NSURLConnectionDataDelegate_protocol/Reference/Reference.html
XCode seems to agree that it is deprecated:
Just in case anyone wonders how I am using the downloader, it is pretty trivial really:
In .h:
#import <UIKit/UIKit.h>
#import "NIAsyncDownloader.h"
@interface DTViewController : UIViewController <NIAsyncDownloaderDelegate>
{
NIAsyncImageDownloader *downloader;
}
@end
And in .m :
#import "DTViewController.h"
@interface DTViewController ()
@end
@implementation DTViewController
- (void)viewDidLoad
{
[super viewDidLoad];
downloader = [[NIAsyncImageDownloader alloc] initWithDataDownloadString:@"http://www.freeimageslive.com/galleries/sports/sportsgames/pics/whitedice1.jpg"];
downloader.delegate = self;
}
-(void) asyncDownloaderDataDownloadComplete:(NSData *)data withError:(bool)error
{
if (data == nil || error)
{
NSLog(@"DOWNLOAD FAILED");
}
else
{
NSLog(@"DOWNLOAD SUCCEEDED");
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
So, summed up, why am I having problems and what to do?
Thanks in advance :)
This may or may not be the problem, but when I set up to do a similar thing I implement the NSURLConnectionDelegate and the NSURLConnectionDataDelegate protocols. I haven't tested on iOS versions previous to 5, but it has worked in both 5 and 6 for me:
@interface NIAsyncImageDownloader : NSObject <NSURLConnectionDelegate, NSURLConnectionDataDelegate> {
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With