When I use NSURLConnection asynchronously to try and get a NSData with my image data in it the image comes back as blank, but when I use dataWithContentsOfURL synchronously I have no problems and I get the image data correctly. Is there any reason why my asynchronous method would be failing?
This works:
NSData *data = [NSData dataWithContentsOfURL: url];
NSLog(#"TEST %#", data);
UIImage *map = [UIImage imageWithData:data];
mapView.image = map;
This doesn't:
//
// MapHttpRequest.m
// GTWeb
//
// Created by Graphic Technologies on 6/21/11.
// Copyright 2011 __MyCompanyName__. All rights reserved.
//
#import "MapHttpRequest.h"
#implementation MapHttpRequest
#synthesize receivedData;
#synthesize dataString;
#synthesize vc;
- (void)request:(NSString *)url fromView:(UIViewController *) theVC
{
vc = theVC;
// Create the request.
NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:url]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
NSLog(#"URL: %#", url);
// 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 hold the received data.
// receivedData is an instance variable declared elsewhere.
receivedData = [[NSMutableData data] retain];
} else {
// Inform the user that the connection failed.
}
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
// This method is called when the server has determined that it
// has enough information to create the NSURLResponse.
// It can be called multiple times, for example in the case of a
// redirect, so each time we reset the data.
// receivedData is an instance variable declared elsewhere.
[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
{
// release the connection, and the data object
[connection release];
// receivedData is declared as a method instance elsewhere
[receivedData release];
// inform the user
NSLog(#"Connection failed! Error - %# %#",
[error localizedDescription],
[[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// do something with the data
// receivedData is declared as a method instance elsewhere
[vc mapImageConnectionFinished:receivedData];
// release the connection, and the data object
[dataString release];
[connection release];
[receivedData release];
}
#end
It looks like you started looking at the guide on http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/URLLoadingSystem/Tasks/UsingNSURLConnection.html but didnt finish reading it :)
You need to implement the methods that will received infomation about the data being received.
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
Its all described in the link i provided.
According to your code, you didn't schedule the connection to run:
[connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
[connection start];
Did you put traces in your delegate's callbacks to make sure they are being called?
Turns out it was giving me a bad request because there was a invisible carriage return or white space. Trimming it off with:
url = [url stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
fixed my problems.
Related
I've tried most of advises from stackoverflow but none of them was good for me.
My client wants to save user data in json with GET request in format:
http://website.com/users/save.php?save={"email":"user#domen.com","name":"Will Smith"}
I'm using objective-c
Please advise
Thanks
Edit
my php file looks like this:
<?php
$save = $_GET['save'];
$fp = fopen("save_users_ww.txt", "a+");
fputs($fp,$save."\r\n");
fclose($fp);
?>
so post don't work for me. Thank you for help again
In case someone else will need a solution, this is my code:
.h file:
#interface WelcomeViewController : UIViewController <NSURLConnectionDelegate>
{
NSMutableData *_responseData;
}
.m file:
-(void)postToDataBaseWithName:(NSString*)nameToPost andEmail:(NSString*)emailToPost {
NSString *str = [NSString stringWithFormat:#"http://website.com/users/save.php?save={\"email\":\"%#\",\"name\":\"%#\"}", emailToPost, nameToPost];
str = [str stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *url = [NSURL URLWithString:str];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
// Create url connection and fire request
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];
if(conn) {
}
}
also add delegate methods to see how it works:
#pragma mark NSURLConnection Delegate Methods
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
// 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
NSLog(#"didReceiveResponse");
_responseData = [[NSMutableData alloc] init];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
// Append the new data to the instance variable you declared
NSLog(#"didReceiveData");
[_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(#"connectionDidFinishLoading");
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
// The request has failed for some reason!
// Check the error var
NSLog(#"didFailWithError = %#", error);
}
-(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;
I am just new in IOS development. I've been trying to figure apple documentations. So I read this page:
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/URLLoadingSystem/Tasks/UsingNSURLConnection.html#//apple_ref/doc/uid/20001836-BAJEAIEE
and this is what I have done:
NSMutableData *testFileType;
// Create the request.
NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:urlString]
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 hold the received data.
// receivedData is an instance variable declared elsewhere.
testFileType = [[NSMutableData data] retain];
NSLog(#"the connection is successful");
} else {
// Inform the user that the connection failed.
NSLog(#"the connection is unsuccessful");
}
[testFileType setLength:0];
[testFileType appendData:[NSMutableData data]];
Can anyone tell me what am I missing here?
Just creating the NSURLConnection is not enough. You also need to implement the didReceiveResponse and didFinishLoading delegate methods. Without these the connection downloads the file, but you never get to see it.
NSURLConnection sends a didReceiveResponse for every redirection when the headers are received. Then it sends a didReceiveData with some bytes of the file. Those you need to append to your mutable data. Finally you get a didFinishLoading where you know that you have gotten all data. In case of error you get a didFailWithError instead.
Look at the NSURLConnectionDelegate protocol documentation: https://developer.apple.com/library/mac/ipad/#documentation/Foundation/Reference/NSURLConnectionDelegate_Protocol/Reference/Reference.html
you should implement the following delegate methods:
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(#"Error: %d %#", [error code], [error localizedDescription]);
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
responseData = [NSMutableData data];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[responseData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[responseData writeToFile:savePath atomically:YES];
}
here responseData and savePath are instance variables declared with:
NSMutableData *responseData;
NSString *savePath;
and your class must conforms the NSURLConnectionDataDelegate and NSURLConnectionDelegate protocols.
For the code to work you probably want to set savePath to a working path like this
NSString *savePath = [NSTemporaryDirectory() stringByAppendingPathComponent:#"testfile.txt"];
after the download have finished, you can do anything to the file at savePath as you wish.
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
How can I upload/download data from a server in Cocoa Touch. Here's what I have so far...
-(void)uploadSchedule:(id)sender
{
NSData *content = [NSData dataWithContentsOfFile:self.dataFilePath];
NSString *stuff = [[NSString alloc] initWithData:content encoding:NSASCIIStringEncoding];
NSURL *url = [NSURL URLWithString:#"http://thetis.lunarmania.com"];
NSMutableURLRequest* urlRequest = [[NSMutableURLRequest alloc]initWithURL:url];
[urlRequest setHTTPMethod:#"POST"];
[urlRequest setHTTPBody:[stuff dataUsingEncoding:NSASCIIStringEncoding]];
NSLog(#"great success!");
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
// this method is called when the server has determined that it
// has enough information to create the NSURLResponse
// it can be called multiple times, for example in the case of a
// redirect, so each time we reset the data.
// receivedData is declared as a method instance elsewhere
[receivedData setLength:0];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// append the new data to the receivedData
// receivedData is declared as a method instance elsewhere
[receivedData appendData:data];
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
// release the connection, and the data object
[connection release];
// receivedData is declared as a method instance elsewhere
[receivedData release];
// inform the user
NSLog(#"Connection failed! Error - %# %#",
[error localizedDescription],
[[error userInfo] objectForKey:NSErrorFailingURLStringKey]);
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// do something with the data
UIImage *image = [[UIImage alloc] initWithData:receivedData];
[cat setImage:image];
[image release];
// receivedData is declared as a method instance elsewhere
NSLog(#"Succeeded! Received %d bytes of data",[receivedData length]);
// release the connection, and the data object
[connection release];
[receivedData release];
}
-(void)connection:(NSURLConnection *)connection
didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
if ([challenge previousFailureCount] == 0) {
NSURLCredential *newCredential;
newCredential=[NSURLCredential credentialWithUser:#"ican#moeyo.org"
password:#"icanican"
persistence:NSURLCredentialPersistenceNone];
[[challenge sender] useCredential:newCredential
forAuthenticationChallenge:challenge];
} else {
[[challenge sender] cancelAuthenticationChallenge:challenge];
// inform the user that the user name and password
// in the preferences are incorrect
//[self showPreferencesCredentialsAreIncorrectPanel:self];
}
}
I'm so lost...
The code crashes because you over-release connection. Review the Cocoa memory management rules.
Aside from that, you'll have to be more specific about what problem you're having with it.
BTW, the term is “instance variable”, not “method instance”. An instance variable is a variable inside of an instance, and has nothing to do with methods.
This has been covered here:
NSURLRequest - encode url for NSURLRequest POST Body (iPhone objective-C)
The accepted answer uses ASIHTTPRequest which is similar to one I've used, and makes it really easy to post/get from an HTML form. Here's an example (from past stackoverflow)
ASIFormDataRequest *request = [[[ASIFormDataRequest alloc] initWithURL:#"http://someSite.com"] autorelease];
[request setPostValue:#"myValue1" forKey:#"myFormField1"];
[request setPostValue:#"myValue2" forKey:#"myFormField2"];
// etc.
[request start];
NSError *error = [request error];
if (!error)
NSString *response = [request responseString];
And if your file is big, you should better use NSFilehandle, to write data inside didReceiveData, instead of appending.