Accessing FTP server from iPad using Objective C - objective-c

I have this code that is trying to access an FTP using the URL. But I cant get access because it's username and password protected. How do I implement that so I can get into the server? Here is my code:
- (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
{
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
NSLog(#"Succeeded! Received %d bytes of data",[receivedData length]);
// release the connection, and the data object
//[connection release];
//[receivedData release];
}
-(IBAction)getURL:(id)sender {
NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:#"ftp://10.0.1.***/App_Data/text.txt"]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
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];
} else {
// Inform the user that the connection failed.
NSLog(#"connection failed");
}}

The user id and password can be embedded in the URL:
ftp://userid:password#10.0.1.***/App_Data/text.txt

Related

What is the proper way to handle network connections?

my app is using network connections as in here:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
.
.
.
receivedData = [[NSMutableData alloc] init];
}
.
-(void) dataFromWeb{
request = [[NSURLRequest alloc] initWithURL: url];
theConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
if (theConnection) {
receivedData = [[NSMutableData data] retain];
NSLog(#"** NSURL request sent !");
} else {
NSLog(#"Connection failed");
}
.
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
.
.
.
[theConnection release];
[request release];
// Here - using receivedData
[receivedData release];
}
.
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[receivedData setLength:0];
}
.
- (void)connection:(NSURLConnection *)connection
didFailWithError:(NSError *)error
{
[theConnection release];
[request release];
[receivedData release];
}
.
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[receivedData appendData:data];
}
. Down the road in the app is this snippet (onButtonPressed):
if (theConnection) {
// Create the NSMutableData to hold the received data.
// receivedData is an instance variable declared elsewhere.
receivedData = [[NSMutableData data] retain];
} else {
NSLog(#"Connection failed");
}
What I want to understand is:
If I wanted to create another simultaneous URLRequest, would I need to use a different connection so that data arriving from the web won't mix up upon retrieval?
In this code, what happens is that sometimes the code would crash on the line of the function didReceiveResponse() setLength:0, when the app crashed I saw receivedData=nil should I change the line to
if(receivedData!=nil)
[receivedData setLength:0];
else
receivedData = [[NSMutableData data] retain];
I am not so sure what this line is doing receivedData = [[NSMutableData data] retain];
I think that the easiest way to handle 2 connections is duplicating the NSMutableData. I use in that way, and it works perfectly for me.
Fist you do this in the point you want the second connection:
receivedData2 = [[NSMutableData alloc] init];
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
if (receivedData2) {
[receivedData2 setLength:0];
}
else
{
[receivedData setLength:0];
}
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
if (receivedData2) {
[receivedData2 appendData:data];
}
else {
[receivedData appendData:data];
}
}
And then, in the method you ask for receivedData2 or receivedData
And when you use it don´t forget to do:
receivedData2=nil;
[receivedData2 setLength:0];
You would of course need a different NSURLConnection.
You can do that, but better find out, why it is nil, because it shouldn't.
It allocates an empty NSMutableData object. But this seems like ugly code for me, because you create an autoreleased object and retain it. Better write [NSMutableData new] or [[NSMutableData alloc] init].

HTTPS request with Cocoa/objective-C

I need to make an HTTPS request from my application in order to fetch some data. I used to be able to do it using this method here
-(void)Authenticate
{
self.responseData = [NSMutableData data];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"https://10.84.4.2:8444/fish-mobile/GetPIN.jsp?MSISDN=12345"]];
//NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[responseData setLength:0];
}
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace {
return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust];
}
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge: (NSURLAuthenticationChallenge *)challenge {
[challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
[challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[responseData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
self.responseData = nil;
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
NSLog(#"%#", responseString);
}
However this is not working since I upgraded my code, my old application that has this code still works, but if I create a new application and poste this code in I get an error around
[responseData setLength:0];
and
[responseData appendData:data];
It says no visible #interface for NSString declares setLength or appenddata.
Could someone tell me why this is not working?
Thanks in advance
Shorted it to this
-(void) testme: (NSString *) link{
NSURL * url = [NSURL URLWithString:link];
NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:url];
[request addValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request setHTTPMethod:#"GET"];
[[NSURLConnection alloc]initWithRequest:request delegate:self startImmediately:YES];
}
And the methods are
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace {
return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust];
}
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
[challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
[challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSString *s = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"%#", s);
}
Works fine
Sounds to me like your responseData instance variable is being somehow typecasted to NSString. How is the responseData ivar defined, and are you doing any other operations on it, except for the delegate ones you just posted?

JSON objects from URL connection displayed in tableview

#pragma mark -
#pragma mark Fetch loans from internet
-(void)loadData
{
self.responseData = [NSMutableData data];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:
#"http://192.168.1.104:8080/Test/ItemGroup.jsp"]];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[responseData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[responseData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
[connection release];
self.responseData = nil;
}
#pragma mark -
#pragma mark Process loan data
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[connection release];
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
self.responseData = nil;
array=[responseString JSONValue];
NSMutableString *text=[NSMutableString stringWithString:#"Values:\n"];
for (int i=0; i <[array count]; i++) {
[text appendFormat:#"%#\n",[array objectAtIndex:i]];
// NSLog(#"Values:""%#\n",array);
}
}
You can use RestKit (a Cocoa RESTful web services framework) to fetch the data and use the object mapping feature to map returned data to an array of objects.
The example given in the RESTKit Object Mapping wiki maps a JSON doc into an array of Article instances: https://github.com/RestKit/RestKit/wiki/Object-mapping

How to return data directly which was loaded by NSURLConnection if delegate functions are needed?

A short explanation what I want to do: I'm using NSURLConnection to connect to a SSL webpage which is my API. The servers certificate is a self signed one so you have to accept it, for example in a web browser. I've found a solution on Stack Overflow how to do the trick (How to use NSURLConnection to connect with SSL for an untrusted cert?)
So I've added the NSURLConnection delegate to use methods like "didReceiveAuthenticationChallenge". As a result of that I cannot use this:
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&error];
because there is no possibility to use the delegate functions in this case. My question is the following: I need a function which looks like this:
- (NSDictionary *)getData : (NSArray *)parameter {
[...|
NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[...]
return myDictionary;
}
how can I return a NSDictionary by using this? As far as you know the delegate function of NSURLConnection are called now and the response isn't available at this point. The problem is that the view controller depends on this response so I need to return the dictionary directly... Does anybody know a solution for this? What about a callback function?
okay, I've found a solution for that. A very good thing is to use blocks in objective-c.
First of all you have to add some methods to NSURLRequest and NSURL:
#implementation NSURLRequest (URLFetcher)
- (void)fetchDataWithResponseBlock:(void (^)(FetchResponse *response))block {
FetchResponse *response = [[FetchResponse alloc] initWithBlock:block];
[[NSURLConnection connectionWithRequest:self delegate:response] start];
[response release];
}
#end
#implementation NSURL (URLFetcher)
- (void)fetchDataWithResponseBlock:(void (^)(FetchResponse *response))block {
[[NSURLRequest requestWithURL:self] fetchDataWithResponseBlock:block];
}
#end
And than just implement the follwing class:
#implementation FetchResponse
- (id)initWithBlock:(void(^)(FetchResponse *response))block {
if ((self = [super init])) {
_block = [block copy];
}
return self;
}
- (NSData *)data {
return _data;
}
- (NSURLResponse *)response {
return _response;
}
- (NSError *)error {
return _error;
}
- (NSInteger)statusCode {
if ([_response isKindOfClass:[NSHTTPURLResponse class]]) return [(NSHTTPURLResponse *)_response statusCode];
return 0;
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
_response = response;
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
if (!_data) _data = [[NSMutableData alloc] init];
[_data appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
_block(self);
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
_error = error;
_block(self);
}
Now you can do the follwing, some kind of callback function:
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"http://..."];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setValue:#"application/json" forHTTPHeaderField:#"accept"];
[request fetchDataWithResponseBlock:^(FetchResponse *response) {
if (response.error || response.statusCode != 200)
NSLog(#"Error: %#", response.error);
else {
//use response.data
}
}];
Here you can find the orginal german solution by ICNH: Asynchrones I/O mit Bloecken
Thank you very much for this!
My suggestion would be to use some other delegate methods for NSURLConnection like connection:didReceiveResponse: or connection:didReceiveData:. You should probably keep a use a set up like so:
#interface MyClass : NSObject {
…
NSMutableData *responseData;
}
…
#end
- (void)startConnection {
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:request delegate:self];
if (theConnection) {
responseData = [[NSMutableData data] retain];
} else {
// connection failed
}
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
// connection could have been redirected, reset the data
[responseData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[responseData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// connection is done, do what you want
………
// don't leak the connection or the response when you are done with them
[connection release];
[responseData release];
}
// for your authentication challenge
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace (NSURLProtectionSpace *)protectionSpace {
return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust];
}
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
if ([trustedHosts containsObject:challenge.protectionSpace.host])
[challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
[challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
}

Instructions in viewdidload not being taken care of

I am facing an annoying problem. I have an application who is basicly made of several methods:
viewDidload, connection:didReceiveResponse, connection:didReceiveData...
In my viewDidload, I define a NSURLRequest to a personal websiten, and right after and before it I added a label.text=#"xxx". I know the problem doesn't come from linking the label in IB because it used to display what I wanted.
But now it seems none of those two label.text instructions are working even though I know my NSURLRequest works because the number of bytes received changes when I change the website... Why is that ? And I'm guessing the other instructions that come after aren't working either.
I will give more details when I can in case anyone can enlighten me on this.
Have a good day and thanks for your help
- (void)viewDidLoad {
[super viewDidLoad];
label.text=#"rrr";
request=[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://mywebsite.aspx?example=5"] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
label.text=#"aeza";
NSURLConnection *connection=[[NSURLConnection alloc] initWithRequest:request delegate:self];
if (connection) {
receiveddata=[[NSMutableData data] retain];
label.text=#"NO BUG";
}
else {
label.text=#"BUG";
}
datastring = [[NSString alloc] initWithData:receiveddata encoding:NSUTF8StringEncoding];
components=[datastring componentsSeparatedByString:#"|"];
label.text=datastring;
[datastring release];
}
-(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
{
[connection release];
[receiveddata release];
NSLog(#"Connection failed! Error - %# %#",
[error localizedDescription],
[[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);
}
-(void) connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(#"Succeeded! Received %d bytes of data",[receiveddata length]);
[connection release];
[receiveddata release];
}
#end
I would move that setup logic to -viewWillAppear, rather than the -viewDidLoad.
Nevermind, I got this to work by moving instructions to another method.