NSURLConnection delegate methods are not being called - ios

I am trying to download a set of files from a web server using NSURLConnection but at the point the connection appears to be made, the connection's delegate methods never get fired and so the file never gets downloaded. I have read many answers on SO and other sources and have tried the fixes that have been advised but to no avail, which makes me think I have made a different mistake here.
I have a viewController (InitViewController.m) which loads another class's method:
GetData *getDataInstance = [[GetData alloc] init];
[getDataInstance startUpdate];
GetData.m then does some checking and runs the class in charge of getting the files:
GetFiles *getFilesInstance = [[GetFiles alloc] init];
[getFilesInstance doFilesNeedDownloading];
doFilesNeedDowngoading method checks to see if we need the file and then runs getFiles:
-(void)getFile//:(NSString *) fullURL
{
// I have checked if the connection is run on the main thread and it is
NSLog(#"Is%# main thread", ([NSThread isMainThread] ? #"" : #" NOT"));
NSURL *downloadURL = [NSURL URLWithString:fullURL];
NSMutableURLRequest *dlRequest = [NSMutableURLRequest requestWithURL:downloadURL];
NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:dlRequest delegate:self];
[theConnection scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
[theConnection start];
if(theConnection) { //me checking for connection which is 'true'
NSLog(#"Connection for %# worked", fullURL);
} else {
NSLog(#"Connection for %# failed", fullURL);
}
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
responseData = [[NSMutableData alloc] init];
NSString *fileName = [[NSURL URLWithString:fullURL] lastPathComponent];
NSString *filePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentationDirectory, NSUserDomainMask, YES) objectAtIndex:0]stringByAppendingPathComponent:fileName];
[[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil];
file = [NSFileHandle fileHandleForUpdatingAtPath:filePath];
[file seekToEndOfFile];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[responseData appendData:data];
[file seekToEndOfFile];
[file writeData:data];
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
[file closeFile];
}
I did originally fire the getDataInstance startUpdate in a separate thread in an update to have the 'getting data' part of the app separate to the 'UI building' part of the app and thought this might be the issue but for now I have remove that and even put in'[theConnection scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]' as per other answers to this kind of question on SO.
I'm sure there will be something really obvious that I have missed, any ideas?
Thanks,
EDIT
I have now tried this code again but in the initViewController so this is pretty much the first thing that is fired when the app loads. This is no longer in another class or thread etc.:
-(void)getFile
{
fullURL = #"http://myURL.com/terms-and-conditions.txt";
NSURL *downloadURL = [NSURL URLWithString:fullURL];
NSMutableURLRequest *dlRequest = [NSMutableURLRequest requestWithURL:downloadURL];
NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:dlRequest delegate:self];
[theConnection start];
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
responseData = [[NSMutableData alloc] init];
NSString *fileName = [[NSURL URLWithString:fullURL] lastPathComponent];
NSString *filePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentationDirectory, NSUserDomainMask, YES) objectAtIndex:0]stringByAppendingPathComponent:fileName];
[[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil];
file = [NSFileHandle fileHandleForUpdatingAtPath:filePath];
[file seekToEndOfFile];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[responseData appendData:data];
[file seekToEndOfFile];
[file writeData:data];
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
[file closeFile];
}
getFile gets fired but it's delegate methods still don't get fired?

If you create NSURLConnection in other thread you have to manually start the run loop.
Try with this:
-(void)getFile
{
NSURL *downloadURL = [NSURL URLWithString:fullURL];
NSMutableURLRequest *dlRequest = [NSMutableURLRequest requestWithURL:downloadURL];
NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:dlRequest delegate:self];
[theConnection scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] run];
[theConnection start];
if(theConnection) { //me checking for connection which is 'true'
NSLog(#"Connection for %# worked", fullURL);
} else {
NSLog(#"Connection for %# failed", fullURL);
}
}

I had this problems too when I wanted to start NSURLConnection in a concurrent NSOperation.
Performing connection on main thread helped me solve the problem.
- (void)start {
if (![NSThread isMainThread]) {
[self performSelectorOnMainThread:#selector(start)
withObject:nil
waitUntilDone:NO];
return;
}
}
Also scheduling sonnection in [NSRunLoop currentRunLoop] helped me to solve the problem:
self.connection = [[NSURLConnection alloc] initWithRequest:request
delegate:self
startImmediately:NO];
[self.connection scheduleInRunLoop:[NSRunLoop currentRunLoop]
forMode:NSRunLoopCommonModes];
[self.connection start];
You can take a look how it's done in CSMessage class that is part of CSUtils framework. Feel free to use given code on your own: https://github.com/cloverstudio/CSUtils

Put delegate in your class.h like:
#interface InitViewController : UIViewController<NSURLConnectionDelegate,NSURLConnectionDataDelegate>

In the end I re-wrote the whole class and got the delegates firing.
NSString *currentURL = [NSString stringWithFormat:#"%#/api/sync", apiURL];
NSLog(#"URL = %#", currentURL);
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:currentURL]];
[request addValue:#"application/json" forHTTPHeaderField:(#"Accept")];
NSURLResponse *response = nil;
NSError *error = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
Here are the delegates that now fire:
- (void)connection:(FileURLConnection*)connection didReceiveResponse:(NSURLResponse *)response
{
NSString *fileName = [[response URL] lastPathComponent];
NSString *filePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]stringByAppendingPathComponent:fileName];
[[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil];
connection.file = [NSFileHandle fileHandleForUpdatingAtPath:filePath];
}
- (void)connection:(FileURLConnection *)connection didReceiveData:(NSData *)data
{
[connection.file writeData:data];
}
- (NSCachedURLResponse *)connection:(FileURLConnection *)connection willCacheResponse:(NSCachedURLResponse*)cachedResponse
{
return nil;
}
- (void)connectionDidFinishLoading:(FileURLConnection *)connection
{
[connection.file closeFile];
}
- (void)connection:(FileURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(#"GetFiles - didFailWithError - error : %# for URL %#", error, connection.currentRequest.URL);
}
The class now downloads the file (from my own API) and saves it on the device.

Just change this line and rest keep as it is in your code. Keep the scheduleInRunLoop line also.
NSURLConnection * connection = [[NSURLConnection alloc] initWithRequest:request
delegate:self startImmediately:NO];

Related

NSUrlConnection Delegate methods are not getting called from helper class

I have to do SSL pinning so need to verify server side SSL certificate.
SO I have to use NSURL delegates. I have a helper class in which I have created method which returns me login response:
- (NSData *)sendSynchronousRequest:(NSString *)strNewLoginRequest
returningResponse:(NSURLResponse **)response
error:(NSError **)error {
NSMutableURLRequest *finalRequest = nil;
NSURL *url= [NSURL URLWithString:const_url];
finalRequest = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:30.0];
NSData *requestData = [NSData dataWithBytes:[strLoginRequest UTF8String] length:[strLoginRequest length]];
self.connection = [[NSURLConnection alloc] initWithRequest:finalRequest delegate:self startImmediately:NO];
NSRunLoop *currentRunLoop = [NSRunLoop currentRunLoop];
[self.connection unscheduleFromRunLoop:currentRunLoop forMode:NSDefaultRunLoopMode];
[self.connection scheduleInRunLoop:currentRunLoop forMode:#"connectionRunLoopMode"];
[self.connection start];
while ([currentRunLoop runMode:#"connectionRunLoopMode" beforeDate:[NSDate distantFuture]]);
return self.mutableResponse;
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
self.response = response;
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
self.mutableResponse = [[NSMutableData alloc]init];
[self.mutableResponse appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
dispatch_async(dispatch_get_main_queue(), ^{
if (loadingView)
{
[loadingView removeView];
}
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Failure" message:#"Network Failure" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alert show];
});
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
if (loadingView)
{
[loadingView removeView];
}
self.resultString = [[NSString alloc] initWithData:self.mutableResponse encoding:NSASCIIStringEncoding];
}
and I am calling this method from another class called ViewController with code
-(void)doLogin
{
self.service = [[SyncCommunicationService alloc]init];
NSData *data = [self.service sendSynchronousRequest:strNewLoginRequest
returningResponse:&response
error:nil];
}
I have tried calling this method in background and on main thread but still delegate methods are not getting called, I have tried many other answers from same website but still couldn't able to solve this issue so please can anybody have a clue what am I doing wrong.
I'm wondering why would anyone use asynchronous request for performing task synchronously? Not to mention this strange way to wait with while statement instead of dispatch_semaphore or something similar.
However, why You even bother with delegate? Just use class method sendSynchronousRequest:returningResponse:error:. I think, it would suffice in your case

Objective C: Downloading File With Progress Bar [duplicate]

This question already has an answer here:
how to display progressbar during downloading video file from the server in to the iphone?
(1 answer)
Closed 9 years ago.
I am trying to put a progress bar that syncs during the download that is happening.
My app now can download a file using with this codes...
pdfData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:#"http://webaddress.com/pro/download/file.pdf"]];
NSString *resourcePDFPath = [[NSString alloc] initWithString:[[[[NSBundle mainBundle] resourcePath] stringByDeletingLastPathComponent] stringByAppendingPathComponent:#"Documents"]];
pdfFilePath = [resourcePDFPath stringByAppendingPathComponent:#"myPDF.pdf"];
[pdfData writeToFile:pdfFilePath atomically:YES];
During the process of this code the app stopped during download, is it normal?
Now what I want is to put a progress bar during that stop time while downloading.
I tried looking into the codes I found online but I'm a bit confused, I think I need a step-by-step-well-explained reference.
Using AFNetworking,
here progress is the UIProgressview
#import <AFNetworking/AFNetworking.h>//add to the header of class
-(void)downloadShowingProgress
{
progress.progress = 0.0;
currentURL=#"http://www.selab.isti.cnr.it/ws-mate/example.pdf";
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:currentURL]];
AFURLConnectionOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *filePath = [[paths objectAtIndex:0] stringByAppendingPathComponent:#"MY_FILENAME_WITH_EXTENTION.pdf"];
operation.outputStream = [NSOutputStream outputStreamToFileAtPath:filePath append:NO];
[operation setDownloadProgressBlock:^(NSUInteger bytesRead, NSUInteger totalBytesRead, NSUInteger totalBytesExpectedToRead) {
progress.progress = (float)totalBytesRead / totalBytesExpectedToRead;
}];
[operation setCompletionBlock:^{
NSLog(#"downloadComplete!");
}];
[operation start];
}
Using NSURLConnection
-(void)downloadWithNsurlconnection
{
NSURL *url = [NSURL URLWithString:currentURL];
NSURLRequest *theRequest = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:60];
receivedData = [[NSMutableData alloc] initWithLength:0];
NSURLConnection * connection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self startImmediately:YES];
}
- (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
progress.hidden = NO;
[receivedData setLength:0];
expectedBytes = [response expectedContentLength];
}
- (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[receivedData appendData:data];
float progressive = (float)[receivedData length] / (float)expectedBytes;
[progress setProgress:progressive];
}
- (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}
- (NSCachedURLResponse *) connection:(NSURLConnection *)connection willCacheResponse: (NSCachedURLResponse *)cachedResponse {
return nil;
}
- (void) connectionDidFinishLoading:(NSURLConnection *)connection {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *pdfPath = [documentsDirectory stringByAppendingPathComponent:[currentURL stringByAppendingString:#".mp3"]];
NSLog(#"Succeeded! Received %d bytes of data",[receivedData length]);
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
[receivedData writeToFile:pdfPath atomically:YES];
progress.hidden = YES;
}
Use ASIHTTPRequest.h class and ASINetworkQueue.h for downloading the file.
and use this code for progress bar
request = [ASIHTTPRequest requestWithURL:#"http://webaddress.com/pro/download/file.pdf];
[request setDelegate:self];
[request setDownloadProgressDelegate:progressView];
[request setShowAccurateProgress:YES];
request.shouldContinueWhenAppEntersBackground=YES;
request.allowResumeForFileDownloads=YES;
[request startAsynchronous];
this may help you
I'm afraid it's not normal, use asynchronous method to get the NSData.
First of all you should be clear whether to make a synchronous call or asynchronous.
For mobile apps or any other app asynchronous is preferred one.
Once you are clear use NSURLConnection class to fetch the data from the URL.
Here is the good tutorial.
And for loading you can start progress while starting the request and stop it when you receive connection:didFailWithError: or connectionDidFinishLoading: delegate method.

Issue in NSURL in Objective C

I am trying to execute a async http request. but the call back log is not working. please analyze the code and suggest me the cause of this issue. I have seen the class examples in many places. But here i am calling it from a main function.
#interface HTTP : NSObject
#property (nonatomic,retain) NSMutableData *receivedData;
- (void) get : (NSString *) urlString;
#end
#implementation HTTP
#synthesize receivedData;
- (void)get: (NSString *)urlString {
NSLog ( #"GET: %#", urlString );
self.receivedData = [[NSMutableData alloc] init];
NSURLRequest *request = [[NSURLRequest alloc]
initWithURL: [NSURL URLWithString:urlString]
cachePolicy: NSURLRequestReloadIgnoringLocalCacheData
timeoutInterval: 10
];
NSURLConnection *connection = [[NSURLConnection alloc]
initWithRequest:request
delegate:self
startImmediately:YES];
[connection start];
}
- (void)connection:(NSURLConnection*) connection didReceiveResponse:(NSURLResponse *)response
{
NSLog(#"Response recieved");
}
- (void)connection:(NSURLConnection*) connection didReceiveData:(NSData *)data
{
NSLog(#"Data recieved");
NSString* responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
[receivedData appendData:responseString];
}
#end
int main(const int c , char *arg[]){
HTTP *http = [[HTTP alloc] init];
[http get:#"http://www.apple.com"];
return 0;
}
Your program does not have a "run loop", therefore it terminates immediately after
[http get:#"http://www.apple.com"];
has returned, before any delegate functions are called. (Note that NSURLConnection works asynchronously.)
If this is for a stand-alone OS X application, you could to the following:
int main(const int c , char *arg[]){
HTTP *http = [[HTTP alloc] init];
[http get:#"http://www.apple.com"];
NSRunLoop *theRL = [NSRunLoop currentRunLoop];
while (shouldKeepRunning && [theRL runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]);
return 0;
}
where shouldKeepRunning is a (global) Boolean variable that is initially YES, and set to NO in
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
shouldKeepRunning = NO;
}
and also in connection:didFailWithError:. Or you add a Boolean property loading to your HTTP class.
If this is for an iOS application or a OS X Cocoa application, then you already have a run loop and don't have to add your own.
/*
Till the application finishes loading, the main thread is kept alive so that the delegate methods are called.
Hence the while loop below.
*/
while(!finished) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
Here is my working code.
#implementation HTTP
#synthesize receivedData,retStr,delegate;
- init {
if ((self = [super init])) {
receivedData = [[NSMutableData alloc] init];
}
return self;
}
- (void)get: (NSString *)urlString {
NSLog ( #"GET: %#", urlString );
self.receivedData = [[NSMutableData alloc] init];
NSURLRequest *request = [[NSURLRequest alloc]
initWithURL: [NSURL URLWithString:urlString]
cachePolicy: NSURLRequestReloadIgnoringLocalCacheData
timeoutInterval: 10
];
NSURLConnection *connection = [[NSURLConnection alloc]
initWithRequest:request
delegate:self
startImmediately:YES];
while(!finished) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
if(!connection) {
NSLog(#"connection failed :(");
} else {
NSLog(#"connection succeeded :)");
}
}
- (void)post:(NSString*)urlString: (NSString*)body: (NSObject*) sender {
// POST
NSMutableString* requestURL = [[NSMutableString alloc] init];
[requestURL appendString:urlString];
NSMutableString* requestBody = [[NSMutableString alloc] initWithString:body];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL: [NSURL URLWithString: [NSString stringWithString:requestURL]]];
NSString* requestBodyString = [NSString stringWithString:requestBody];
NSData *requestData = [NSData dataWithBytes: [requestBodyString UTF8String] length: [requestBodyString length]];
[request setHTTPMethod: #"POST"];
[request setValue:#"text/html; charset=utf-8" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody: requestData];
NSURLConnection *postConn= [[NSURLConnection alloc] initWithRequest:request delegate:sender];
/*
Till the application finishes loading, the main thread is kept alive so that the delegate methods are called.
Hence the while loop below.
*/
while(!finished) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
if(!postConn) {
NSLog(#"POST connection failed :(");
} else {
NSLog(#"POST connection succeeded :)");
}
}
// ====================
// Callbacks
// ====================
#pragma mark NSURLConnection delegate methods
- (NSURLRequest *)connection:(NSURLConnection *)connection
willSendRequest:(NSURLRequest *)request
redirectResponse:(NSURLResponse *)redirectResponse {
NSLog(#"Connection received data, retain count");
return request;
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
NSLog(#"Received response: %#", response);
[receivedData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSLog(#"Received %lu bytes of data", [data length]);
[receivedData appendData:data];
NSLog(#"Received data is now %lu bytes", [receivedData length]);
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSRunAlertPanel(#"Error",[NSString stringWithFormat:#"Could not connect to server.Following error occured:\n\n%#", error], nil, nil, nil);
NSLog(#"Error receiving response: %#", error);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// Once this method is invoked, "responseData" contains the complete result
NSLog(#"Succeeded! Received %lu bytes of data", [receivedData length]);
NSString *dataStr=[[NSString alloc] initWithData:receivedData encoding:NSASCIIStringEncoding] ;
retStr = [NSString stringWithString:dataStr];
finished =TRUE;
// [self returnDcString:dataStr];
// NSLog(#"%#",dataStr);
if ([delegate respondsToSelector:#selector(didFinishDownload:)]) {
NSLog(#"Calling the delegate");
//NSString* dataAsString = [[[NSString alloc] initWithData:receivedData encoding:NSUTF8StringEncoding] autorelease];
// [delegate performSelector:#selector(didFinishDownload:) withObject: dataStr];
}
}
- (void)setDelegate:(id)val
{
delegate = val;
}
- (id)delegate
{
return delegate;
}
#end

iOS - Async NSURLConnection inside NSOperation

I know this question was asked many times on SO, but I didn't manage to make it work in my project...
So, I want to subclass NSOperation and make it download a file using NSURLConnection. What is the right way to do it?
here is my code which doesn't work:
First, I'm adding all my operations in a loop:
DownloadFileOperation *operation;
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
for (int i=0; i<10; i++) {
operation = [[DownloadFileOperation alloc] init];
operation.urlString = pdfUrlString;
[queue addOperation:operation];
operation = nil; }
And here is my subclass:
#interface DownloadHandbookOperation : NSOperation <NSURLConnectionDelegate>
{
}
#property (strong, nonatomic) NSString *urlString;
#end
#implementation DownloadHandbookOperation
{
NSString *filePath;
NSFileHandle *file;
NSURLConnection * connection;
}
- (void)start
{
if (![NSThread isMainThread])
{
[self performSelectorOnMainThread:#selector(start) withObject:nil waitUntilDone:NO];
return;
}
NSURL *url = [[NSURL alloc] initWithString:[self.urlString stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]];
NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url];
[req addValue:#"Basic ***=" forHTTPHeaderField:#"Authorization"];
connection = [[NSURLConnection alloc] initWithRequest:req delegate:self startImmediately:YES];
}
- (void)connection:(NSURLConnection *)conn didReceiveResponse:(NSURLResponse *)response
{
NSString *filename = [[conn.originalRequest.URL absoluteString] lastPathComponent];
filename = [filename stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
filePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:filename];
[[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil];
file = [NSFileHandle fileHandleForUpdatingAtPath:filePath] ;
if (file)
{
[file seekToEndOfFile];
}
else
[self finish];
}
- (void)connection:(NSURLConnection *)conn didReceiveData:(NSData *)data
{
if (file) {
[file seekToEndOfFile];
}
[file writeData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)conn
{
[file closeFile];
[self finish];
}
- (void)connection:(NSURLConnection *)conn didFailWithError:(NSError *)error
{
connection = nil;
[self finish];
}
- (void)cancel
{
[super cancel];
[connection cancel];
}
- (void)finish
{
NSLog(#"operationfinished.");
}
#end
What am I doing wrong?
You need to properly configure your operation to execute as a "concurrent operation"
Concurrency Programming Guide: Configuring Operations for Concurrent Execution
You need to return isConcurrent = YES and properly manage the other state flags, isExecuting and isFinished in a KVO compliant manner.
To illustrate the general idea here is a post from the engineers at Pulse that describes their solution with some easy to follow demo code you can download and review.
Pulse Engineering Blog: Concurrent Downloads using NSOperationQueues **
This code also handles the requirement that NSURLConnection is started on a thread with an active runloop by ensuring that it starts it on the main thread.
(** link is now to archive.org, I think pulse was acquired and have taken their old site down)

Object-c/iOS :How to use ASynchronous to get a data from URL?

My friend saw my code, a part is get a plist data from URL
And he told me not to use Synchronous,Use ASynchronous
But I don't know how to do ASynchronous in simple way
This is the code I use in my program
NSURL *theURL = [[NSURL alloc]initWithString:#"http://someurllink.php" ];
NSURLRequest *theRequest=[NSURLRequest requestWithURL:theURL
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
NSData *returnData = [NSURLConnection sendSynchronousRequest:theRequest returningResponse:nil error:nil];
NSString *listFile = [[NSString alloc] initWithData:returnData encoding:NSUTF8StringEncoding];
self.plist = [listFile propertyList];
[self.tableView reloadData];
[listFile autorelease];
How can I change my code use ASynchronous to get the data ?
Great thanks for all reply and answers : )
Short answer: You can use
+ (NSURLConnection *)connectionWithRequest:(NSURLRequest *)request delegate:(id)delegate;
See NSURLConnectionDelegate for the informal delegate protocol (all methods are optional)
Long answer:
Downloading data asynchronously is not as straightforward as the synchronous method. First you have to create your own data container e.g. a file container
//under documents folder/temp.xml
file = [[SomeUtils getDocumentsDirectory] stringByAppendingPathComponent:#"temp.xml"]
NSFileManager *fileManager = [NSFileManager defaultManager];
if(![fileManager fileExistsAtPath:file]) {
[fileManager createFileAtPath:file contents:nil attributes:nil];
}
When you connect to server:
[NSURLConnection connectionWithRequest:myRequest delegate:self];
You have to fill the container with the data you receive asynchronously:
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSFileHandle *fileHandle = [NSFileHandle fileHandleForUpdatingAtPath:file];
[fileHandle seekToEndOfFile];
[fileHandle writeData:data];
[fileHandle closeFile];
}
You have to manage errors encountered using:
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
If you want to capture the server response:
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse *)response
Handle when connection finished loading:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
For asynchronous fetch of HTML source code, I recommend you to use AFNetworking
1) Then subclass AFHTTPCLient, for example:
//WebClientHelper.h
#import "AFHTTPClient.h"
#interface WebClientHelper : AFHTTPClient{
}
+(WebClientHelper *)sharedClient;
#end
//WebClientHelper.m
#import "WebClientHelper.h"
#import "AFHTTPRequestOperation.h"
NSString *const gWebBaseURL = #"http://dummyBaseURL.com/";
#implementation WebClientHelper
+(WebClientHelper *)sharedClient
{
static WebClientHelper * _sharedClient = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_sharedClient = [[self alloc] initWithBaseURL:[NSURL URLWithString:gWebBaseURL]];
});
return _sharedClient;
}
- (id)initWithBaseURL:(NSURL *)url
{
self = [super initWithBaseURL:url];
if (!self) {
return nil;
}
[self registerHTTPOperationClass:[AFHTTPRequestOperation class]];
return self;
}
#end
2) Request asynchronously HTML source code, put this code in any relevant part
NSString *testNewsURL = #"http://whatever.com";
NSURL *url = [NSURL URLWithString:testNewsURL];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFHTTPRequestOperation *operationHttp =
[[WebClientHelper sharedClient] HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSString *szResponse = [[[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding] autorelease];
NSLog(#"Response: %#", szResponse );
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
NSLog(#"Operation Error: %#", error.localizedDescription);
}];
[[WebClientHelper sharedClient] enqueueHTTPRequestOperation:operationHttp];

Resources