IOS7 NSURLConnection nothing happens - ios

I am quite a newbie to IOS programming and want to user's location to server. I followed iOS developer library and tutorials on the Internet but nothing happens when I run the code. I am using the iOS simulator and it gives me mock locations well and I get NSURLConnection instance. However, nothing happens on server-side.
#import "JLSViewController.h"
#import <CoreLocation/CoreLocation.h>
#import "JLSEventData.h"
#interface JLSViewController ()
#property (nonatomic, strong) CLLocationManager *locationManager;
#property (nonatomic, strong) NSMutableArray *locations;
#end
#implementation JLSViewController
NSMutableData *responseData = nil;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.locations = [[NSMutableArray alloc] init];
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
self.locationManager.delegate = self;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)enabledStateChanged:(id)sender
{
if (self.switchEnabled.on)
{
[self.locationManager startUpdatingLocation];
}
else
{
[self.locationManager stopUpdatingLocation];
}
}
- (void)beginBackgroundUpdateTask: (CLLocation *)location {
}
- (void)endBackgroundUpdateTask {
}
#pragma mark - CLLocationManagerDelegate
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation {
if (newLocation == nil) {
return;
}
if (oldLocation != nil) {
if (newLocation.coordinate.latitude == oldLocation.coordinate.latitude &&
newLocation.coordinate.longitude == oldLocation.coordinate.longitude) {
return;
}
}
NSError *error = nil;
JLSEventData *eventData = [[JLSEventData alloc] initWithLocation: newLocation];
NSString *strData = [eventData toJSON:error];
if (error != nil){
return;
}
if (self.locations.count>5)
[self.locations removeObjectAtIndex:0];
[self.locations addObject:strData];
NSData *requestBodyData = [NSJSONSerialization dataWithJSONObject:self.locations options:NSJSONWritingPrettyPrinted error:&error];
if (error != nil){
return;
}
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//[self beginBackgroundUpdateTask:newLocation];
// Send a synchronous request
NSMutableURLRequest * urlRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString: "http://localhost:8080/mywebservice"]];
[urlRequest setValue:#"application/json; charset=utf-8" forHTTPHeaderField:#"Content-Type"];
[urlRequest setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[urlRequest setHTTPMethod:#"POST"];
//[urlRequest setTimeoutInterval:20];
//NSJSONSerialization dataWithJSONObject
urlRequest.HTTPBody = requestBodyData;
// Create url connection and fire request
[urlRequest setHTTPBody:[NSData dataWithBytes:[strData UTF8String] length:strlen([strData UTF8String])]];
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:urlRequest delegate:self];
if (conn!=nil){
//receivedData = nil;
}
});
}
#pragma mark - NSURLConnection Delegate
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
NSLog(#"==>didReceiveResponse");
// A response has been received, this is where we initialize the instance var you created
// so that we can append data to it in the didReceiveData method
// Furthermore, this method is called each time there is a redirect so reinitializing it
// also serves to clear it
responseData = [[NSMutableData alloc] init];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSLog(#"==>didReceiveData");
// Append the new data to the instance variable you declared
[responseData appendData:data];
}
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection
willCacheResponse:(NSCachedURLResponse*)cachedResponse {
// Return nil to indicate not necessary to store a cached response for this connection
return nil;
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// The request is complete and data has been received
// You can parse the stuff in your instance variable now
NSLog(#"Succeeded! Received %d bytes of data",[responseData length]);
responseData = nil;
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
// The request has failed for some reason!
// Check the error var
NSLog(#"Connection failed! Error - %# %#",
[error localizedDescription],
[[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);
}
/*
*
*/
- (void)parseData {
//Do something
}
#end
Any help would be appreciated.

You are doing the NSURLConnection on a separate thread. And the thread is exiting before the response is received. You either need to do the NSURLConnection on the main thread or you need to keep the thread running until the response is received.

Related

NSURLConnection and NSURLConnectionDataDelegate: connection callbacks are not fired

I want to implement file downloading with progress from my server.
I my code I'm using a custom class which is delegated by
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:#"http://example.com"]];
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"6.0")) {
DownloadCallback *dc = [[DownloadCallback alloc] initWithCallbackProgress:^(long long res){
NSLog(#"%lld", res);
} withCallbackReady:^(long long res){
NSLog(#"READY %lld", res);
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
}];
} withCallbackError:^(NSError * error) {
NSLog(#"READY %#", error.domain);
}];
NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:dc];
// [connection setDelegateQueue:[[NSOperationQueue alloc] init]];
[connection start];
header:
#interface DownloadCallback: NSObject<NSURLConnectionDataDelegate>{
#private void (^_progressHandler)(long long someParameter);
#private void (^_readyHandler)(long long someParameter);
#private void (^_errorHandler)(NSError *someParameter);
}
-(id) initWithCallbackProgress:(void(^)(long long))handler withCallbackReady:(void(^)(long long))handlerReady withCallbackError:(void(^)(NSError*))handlerError;
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response;
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data;
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error;
#end
body:
#implementation DownloadCallback
-(id) initWithCallbackProgress:(void(^)(long long))handler withCallbackReady:(void(^)(long long))handlerReady withCallbackError:(void(^)(NSError*))handlerError{
self = [super init];
if (self) {
_progressHandler = [handler copy];
_readyHandler = [handlerReady copy];
_errorHandler = [handlerError copy];
}
return self;
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
// self.expectedTotalSize = response.expectedContentLength;
// Call completion handler.
if (_readyHandler != nil)
_readyHandler(response.expectedContentLength);
// Clean up.
// [_completionHandler release];
_readyHandler = nil;
_progressHandler = nil;
_errorHandler = nil;
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
// self.recievedData += data.length;
if (_progressHandler != nil)
_progressHandler(data.length);
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
if (_errorHandler != nil)
_errorHandler(error);
}
#end
But the callback events are not fired! At all!
The simple synch code work prefectly:
// Send a synchronous request
NSURLRequest * urlRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://example.com"]];
NSURLResponse * response = nil;
NSError * error = nil;
NSData * data = [NSURLConnection sendSynchronousRequest:urlRequest
returningResponse:&response
error:&error];
if (error == nil) {
// Parse data here
}
But I need a callback! How to resolve it? I've not found in stackoverflow a solution.
Futhermore, if I'm using a simple delegate to major class instead of DownloadCallback the same: the connection callbacks are not fired too.
Add the dealloc method to your callback class and out a breakpoint or log statement in it. See if it is deallocated before the callbacks are called.
If this is the case, your callback class instance is destroyed too soon. Make it a property of a class that will for sure live longer then the request.
Also, you should make sure that this code:
NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:dc];
[connection start];
is called on a thread outlives the connection and has a runloop. The easiest way to achieve this is to call that code on the main-queue. Your code-example does not show on which queue that is called. If it is not working I assume it is because your calling it on a background queue.
You can dispatch to a background queue from the delegate callbacks of you want/need to.
As a sidenote, if you are building something new, you should try and use NSURLSession instead of NSURLConnection. NSURLSession is more secure, easier to use and not deprecated. NSURLConnection is deprecated.

Asynchronous Connection Download Callback

I created a class customDownload with the following methods:
-(NSString *) getTextFromLink: (PreliteRequest *) requestDetails
asyncConnection: (BOOL) isAsync
callbackMethod: (SEL) methodToExecute {
mainRequest = requestDetails;
NSMutableURLRequest *postRequest = [[NSMutableURLRequest alloc] init];
NSURLRequest *getRequest = [[NSURLRequest alloc] init];
NSURLConnection *connection;
NSURLResponse * response = nil;
NSError * error = nil;
if ([[requestDetails getType] isEqualToString:#"POST"]) {
[postRequest setURL:[NSURL URLWithString:[requestDetails getUrl]]];
[postRequest setHTTPMethod:[requestDetails getType]];
[postRequest setValue:[requestDetails getPostLenght] forHTTPHeaderField:#"Content-Length"];
[postRequest setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[postRequest setHTTPBody:[requestDetails getPostParameters]];
if (isAsync) {
tmpMethod = methodToExecute;
connection = [[NSURLConnection alloc] initWithRequest:postRequest delegate:self];
} else
downloadedData = (NSMutableData *)[NSURLConnection sendSynchronousRequest:postRequest returningResponse:&response error:&error];
} else {
getRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:#"%#%#",[requestDetails getUrl],[requestDetails getGetParameters]]]];
if (isAsync) {
tmpMethod = methodToExecute;
connection = [[NSURLConnection alloc] initWithRequest:getRequest delegate:self];
} else
downloadedData = (NSMutableData *)[NSURLConnection sendSynchronousRequest:getRequest returningResponse:&response error:&error];
}
NSString *result=[[NSString alloc]initWithData:downloadedData encoding:NSUTF8StringEncoding];
return result;
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
downloadedData = [[NSMutableData alloc] init];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
// Append the new data to the instance variable you declared
[downloadedData appendData:data];
}
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection
willCacheResponse:(NSCachedURLResponse*)cachedResponse {
return nil;
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
NSString *tmpResult = [[NSString alloc]initWithData:downloadedData encoding:NSUTF8StringEncoding];
[self performSelector:tmpMethod withObject:tmpResult];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
NSLog(#"Connection error: %#",error);
}
In my view controller I declare the previous class and call the only method of that class getTextFromLink.
download = [[customDownload alloc] init];
[download getTextFromLink:request asyncConnection:YES callbackMethod:tmpSelector];
SEL tmpSelector = #selector(printResult:);
-(void) printResult:(NSString *) resultToPrint {
NSLog(#"Risultato: %#",resultToPrint);
}
I pass to getTextFromLink the tmpSelector as parameter because that is the method I would like to call as soon the getTextFromDownloadLink has finished its job.
Actually getTextFromLink execute an asynchronous connection.
What I'm trying to do is to execute something when the asyncronous connection finished to download datas.
I would like to create a callback custom class to do this.
Can anyone help me?
Rather than this selector model, generally people would use blocks for this. For example, define a typedef for your block:
typedef void(^PreliteRequestCompletionHandler)(NSString *string);
Since you're dealing with an asynchronous pattern, you might want to define a property which you can use to save this completion handler to call later:
#property (nonatomic, copy) PreliteRequestCompletionHandler completionHandler;
You can then change that selector parameter to be a block parameter:
-(NSString *) getTextFromLink: (PreliteRequest *) requestDetails
asyncConnection: (BOOL) isAsync
completionHandler: (PreliteRequestCompletionHandler)completionHandler {
self.completionHandler = completionHandler;
// do stuff
}
And then, when you want to call that completion block, you do something like:
NSString *result = ...;
if (self.completionHandler) {
self.completionHandler(result);
}
And then you can now use this new block parameter to your method:
download = [[customDownload alloc] init];
[download getTextFromLink:request asyncConnection:YES completionHandler:^(NSString *result) {
NSLog(#"Risultato: %#", result);
}];

Same code showing different behaviour in XCode

-(IBAction)onButtonClick:(id)sender
{
DowloadFilesManager* downManager1=[[DowloadFilesManager alloc] init];
DowloadFilesManager* downManager2=[[DowloadFilesManager alloc] init];
DowloadFilesManager* downManager3=[[DowloadFilesManager alloc] init];
[downManager1 downloadURL:#"http://localhost/banners/banner1.jpg" destPath:#"/Users/varunisac/Desktop/samples/godisgreat.jpg"];
[downManager2 downloadURL:#"http://localhost/banners/banner1.jpg" destPath:#"/Users/varunisac/Desktop/samples/godisgreat1.jpg"];
[downManager3 downloadURL:#"http://localhost/banners/banner1.jpg" destPath:#"/Users/varunisac/Desktop/samples/godisgreat2.jpg"];
NSLog(#"Finished Succesfully");
}
1)The Above code works Perfect
2) It downloads the jpgs after firing the following event function.
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(#"Succeeded! Received %d bytes of data",[receivedData length]);
[receivedData writeToFile:toFile atomically:YES];
theConnection = nil;
receivedData = nil;
}
But It DOES NOT fires any event methods while i tried on another programme after importing the "DowloadFilesManager.h" and "DowloadFilesManager.m" which runs on the same XCode on the same Mac machine with the server URLs reachable.Can anyone suggest a solution ? Am i missing anything? I tried Clean etc...but doesnt work. Following is the DowloadFilesManager class which i used:
#import "DowloadFilesManager.h"
#implementation DowloadFilesManager
#synthesize toFile;
#synthesize toURL;
#synthesize theConnection;
-(void) downloadURL:(NSString *) urlStr destPath:(NSString *) destPath
{
toURL=urlStr;
toFile=destPath;
// Create the request.
NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:toURL]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
receivedData = [[NSMutableData alloc] init];
// Create the NSMutableData to hold the received data.
// receivedData is an instance variable declared elsewhere.
// [receivedData dataWithCapacity: 0];
// create the connection with the request
// and start loading the data
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if (!theConnection) {
// Release the receivedData object.
receivedData = nil;
// Inform the user that the connection failed.
}
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[receivedData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// Append the new data to receivedData.
// receivedData is an instance variable declared elsewhere.
[receivedData appendData:data];
}
- (void)connection:(NSURLConnection *)connection
didFailWithError:(NSError *)error
{
theConnection = nil;
receivedData = nil;
// inform the user
NSLog(#"Connection failed! Error - %# %#",
[error localizedDescription],
[[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(#"Succeeded! Received %d bytes of data",[receivedData length]);
[receivedData writeToFile:toFile atomically:YES];
theConnection = nil;
receivedData = nil;
}
#end
Within - (void)downloadURL:destPath:, you have created a local variable called theConnection:
NSURLConnection *theConnection = [...];
and when the method ends, this will go out of scope and be destroyed.
What you want is the following, to use your property to persist the connection object:
self.theConnection = [...];
Also, a better approach to signal failure would be to make that method return BOOL and use this statement:
return self.theConnection != nil;

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

NSURLConnection with ARC not receiving Data

I'm fairly new to iOS Development and I'm trying to get content from an URL. I'm using the Apple tutorial for using NSURLConnection, everything is working but I'm not getting data. I've looked around and couldn't find an answer to my problem. I'm also using ARC in my project, maybe that causes the problem?
Here is the code I'm using, starting with my header file:
#interface ViewController : UIViewController
#property (nonatomic, retain) NSMutableData *receivedData;
#end
implementation file:
#implementation ViewController
#synthesize receivedData;
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"1. viewDidLoad");
// Create the request
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.apple.com/"] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
// Create the connection with the request and start loading the data
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
if (connection) {
NSLog(#"2. connection succeeded");
receivedData = [NSMutableData data];
} else {
NSLog(#"2. connection failed");
}
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
NSLog(#"3. didReceiveResponse");
[receivedData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[receivedData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(#"4. Connection failed! Error - %# %#", [error localizedDescription], [[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(#"4. Succeeded! Received %d bytes of data", [receivedData length]);
}
All the NSLog are working, but it keeps saying receivedData has 0 bytes. I couldn't find an answer to my problem so I hope I can find my answer with this question.
I have translated the Using NSURLConnection part of the URL Loading System Programming Guide using ARC.
//
// MyConnection.h
//
#import <Foundation/Foundation.h>
#interface MyConnection : NSObject
- (void)start;
#property NSMutableData *receivedData;
#end
//
// MyConnection.m
//
#import "MyConnection.h"
#implementation MyConnection
- (void)start {
// Create the request
NSURLRequest *theRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.apple.com"] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
// Create the connection with the request and start loading the data
NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if (theConnection) {
// Create the NSMUtableData to fold the received data
// ReceivedData is an instance variable declared elsewhere
_receivedData = [NSMutableData data];
}
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[_receivedData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[_receivedData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
// Inform the user
NSLog(#"Connectionfailed! Error - %# %#",
[error localizedDescription],
[[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// Do something with the data
NSLog(#"Succeeded! Recevied %d bytes of data", [_receivedData length]);
}
#end
Just for the sake of completion. I've had the same problem, with cause in threading. If the thread that owns the NSURLConnection object is different than the thread that owns the delegate, the delegate will not receive notifications. That means that the error in connection would also be gone.
So make sure you create NSURLConnection on same thread that you created the delegate.
You need to start the connection.
You could, for example, use – initWithRequest:delegate:startImmediately:.
An even smaller change to your existing code would be to just use - start on your connection on the if branch:
NSURLConnection *connection = [[NSURLConnection alloc]
initWithRequest:request
delegate:self
startImmediately:NO
];
if (connection) {
NSLog(#"2. connection succeeded");
receivedData = [NSMutableData data];
[connection start];
} else {
NSLog(#"2. connection failed");
}
You can find the reference manual for NSURLConnection here

Resources