Requesting Data from a web server on iOS device - iphone

Currently, the way our app works is we download a text file that describes the information we want. Then we use NSURLConnection and request that one packet that the text file describes. Then we ask for the next packet, wait for it to come in, check it, then ask for the next packet.
Is there a better way to do this without the text file? I feel like I should be able to have the app say, "InformationForJohnDoe" and then the server will just start sending all the packets for JohnDoe, but in this scenario, I don't know how I'd know which data is which in my connectionDidFinishLoading delegate method.
The web service implementation looks like this:
[WebGet(UriTemplate = "GetTestData/{file}")]
public Stream GetTestData(string file)
{
string fileName =
"\\testdirectory" + file;
if (File.Exists(fileName))
{
FileStream stream = File.OpenRead(fileName);
if (WebOperationContext.Current != null)
{
WebOperationContext.Current.OutgoingResponse.ContentType = "text/.txt";
}
return stream;
}
return null;
}
I'm not much of a C# person. I've only just started in C# and web services.

the Idea is that you append to a NSData you define in the class the NSData you get from the
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
method.
Then, in the
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
method, you know that all data is completely loaded and ready for use.
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
NSLog(#"Connection didReceiveData of length: %u", data.length);
[self.dataData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// do seomething with self.dataData
}

Related

NSURLConnectionDownloadDelegate method not getting called

i m working on a project that connect to server and download data from it. i like to support resume download if connection gets interrupt. my approach is to save the downloaded portion of data to a destination file; and if connection gets interrupted, i want to mark the downloaded portion using connection:didWriteData:totalBytesWritten:expectedTotalBytes and later resume from the stopped portion with server.
my code:
- (IBAction)connectToServer:(UIButton *)sender
{
// setup url and send request to server
NSURL *url = [NSURL URLWithString:BASED_URL];
self.urlRequest = [[NSMutableURLRequest alloc] initWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
self.urlConnection = [[NSURLConnection alloc] initWithRequest:self.urlRequest delegate:self];
// start receive data if connection established
if (self.urlConnection){
self.receivedData = [NSMutableData data];
NSLog(#"starting to receive data");
} else {
// handle error
NSLog(#"failed to connect to server");
}
}
- (void)doSomethingWithData
{
// handle data here
}
#pragma NSURLConnectionDataDelegate
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[self.receivedData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// received data
[self.receivedData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
// error connection
NSLog(#"connection failed");
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(#"Data receiving succeed, received: %d bytes of data", [self.receivedData length]);
}
- (void)connection:(NSURLConnection *)connection didWriteData:(long long)bytesWritten totalBytesWritten:(long long)totalBytesWritten expectedTotalBytes:(long long)expectedTotalBytes
{
NSLog(#"not getting called");
}
my question is how come the "connection:didWriteData:totalBytesWritten:expectedTotalBytes" method never get called?
thanks so much!
chris
Have u added this in .h file:
#interface yourViewContoller : UIViewController <NSURLConnectionDataDelegate, NSURLConnectionDelegate>
According to Apple's documentation:
The NSURLConnectionDownloadDelegate protocol describes methods that should be implemented by the delegate of instances of NSURLConnection created using Newsstand Kit’s downloadWithDelegate: method.
Also, it says:
If you are using NSURLConnection directly, your delegate class should instead implement the methods defined in the NSURLConnectionDataDelegate protocol.

NSURLConnection caching and receiving data

Quick question: On the method
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
from the NSURLConnectionDataDelegate, if I don't append the data given by the method on my NSData, will it be lost? or does the connection save it somewhere as well?
No, it's not saved anywhere. If you want to keep it, you must do so yourself.
typically this method is where you would keep track of your data, with an NSMutableData instance variable:
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[myData appendData:data];
}

Why NSURLConnection blocks my UI?

I've been reading several threads and questions about this issue but I didn't find the solution.
I have some asynchronous calls performed with
[NSURLConnection connectionWithRequest:anURLRequest delegate:self];
The problem is that I want the interface to be operative but it is blocked until the connection is finished.
Is this solved launching another thread? Where is exactly the problem?
EDIT
Ok, after retrieve data I parse it with NSXMLParser, that do it synchronously and blocks main thread. Is this correct? Then, maybe I need to parse in another thread. Anyone has a guide?
From the docs:
Messages to the delegate will be sent on the thread that calls this method. For the connection to work correctly the calling thread’s run loop must be operating in the default run loop mode.
Are you sure that this code is being called on a run loop in default mode and not from a thread created by yourself with a different type of run loop mode?
The UI should not be locking up when you use connectionWithRequest. Try creating a label in your UI and have your connection update it with the current amount of data, like so:
- (void)downloadContentFromUrl:(NSURL *)url {
NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10.0];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
if (connection) {
receivedData = [[NSMutableData data] retain];
self.downloadProgressLabel.text = #"Downloading...";
} else {
// oh noes!
}
}
- (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[receivedData setLength:0];
}
- (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[receivedData appendData:data];
int kb = [receivedData length] / 1024;
self.downloadProgressLabel.text = [NSString stringWithFormat:#"Downloaded\n%d kB", kb];
}
connectionWithRequest does indeed run in it's own thread - no need for you to worry about this. In fact it must be started from the main thread. Check out the NSUrlConnection doc for more info.
+ (id)connectionWithRequest:(NSURLRequest *)request delegate:(id)delegate];
This method should create an asynchronous-request (that means that it runs in the background and it doesn't block the UI). You should check if there's another class/method in your file that blocks the UI (for example NSData's '+ (NSData *)dataWithContentsOfURL:(NSURL *)URL').
I don't know if it could help anyone, but I've the same problem (asynchronous URL request blocking the UI) but it was due to:
NSLog(#"dataReceived: %#", data);
in the connectionDidReceiveData method.
In my case I was trying to update the UIProgressView.progress property. I calculated the new value like that
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
[self.progress setProgress:self.downloadedData.length / self.fileSize ];
[self.downloadedData appendData:data];
}
Which doesn't work, I replaced this snippet of code with
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
self.downloadedSize += data.length;
[self.progress setProgress:self.downloadedSize / self.fileSize ];
[self.downloadedData appendData:data];
}
And now the progress view updates with no problem.

Multiple NSURLConnection & NSRunLoop

I am trying to speed up my application download speed. I used Asynchronous NSURLConnection to download contents from the server, it was working fine with one connection.
I use the code from this post to implement multiple delegate objects. Multiple NSURLConnection delegates in Objective-C
When I created 2 NSURLConnection objects, each one is trying to download different files.
The callback didReceiveData routine was called but the it only received data of the first NSURLConnection object until the first connection was done then it started to receive the data from the second NSURLConnection. I want these two connections to receive data at the same time,what should I do? Here is my current code.
-(IBAction) startDownloadClicked :(id) sender
{
while (bDownloading)
{
int nCurrentCon = 0;
while (nCurrentCon < 2)
{
[self downloadAFile:[filenameArray objectAtIndex:nCurrentCon]];
nCurrentCon++;
}
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.5]];
}
}
- (void) downloadAFile: (NSString*) filename
{
NSString* urlstr = #"ftp://myftpusername:password#hostname";
NSURLRequest* myreq = [NSURLRequest requestWithURL:[NSURL URLWithString:urlstr]];
DownloadDelegate* dd = [[DownloadDelegate alloc] init]; //create delegate object
MyURLConnection* myConnection = [[MyURLConnection alloc] initWithRequest:myreq delegate:dd
startImmediately:YES];
}
Then in my Delegate Object, I implemented these routines
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[receiveBuffer setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
NSLog(#"receiving data for %#", targetFileName); //the file name were set when this delegate object is initialized.
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(#"Download Failed with Error - %# %#",
[error localizedDescription],
[[error userInfo] objectForKey:NSErrorFailingURLStringKey]);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(#"File %# - downloaded.", targetFileName);
}
Your code looks okay. I have a similar setup that works successfully (although there seems to be a limit of four concurrent conections).
The main difference between your and my code is that you use FTP while I use HTTP. Why don't you try it with HTTP connections just to see whether you have run into a restriction of FTP connections on the iPhone?

how to access mysql from iphone

i'm a beginner to iphone.i want to create a login page for my application.i cant figure out how to connect to a php page and retrieve corresponding data from mysql database to the iphone.could any one guide me how to go about it.
what does the iphone have to do with a connection between php and mysql ?
PHP will run with on a web server probably apache installed on some computer and it will connect to a MySQL db .. and u will access that php page from your iphone with a browser. Not sure what part will the iphone have in all this other than providing the browser
You might want to have a look at NSURLRequest which you can use with a NSURLConnection to send e.g. GET-Parameters to a URL. You can then implment the NSURLConnectionDelegate to respond to incoming data:
1) setup connection
receivedData =[NSMutableData data];
NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:url]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:20.0];
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
2) Setup delegate methods in self:
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse*)response {
NSHTTPURLResponse * httpResponse = (NSHTTPURLResponse *) response;
if([httpResponse statusCode]==200)
[receivedData setLength:0];
else
NSLog(#"Http-Reponse %u",[httpResponse statusCode]);
// HANDLE ERROR!
}
- (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 {
// HANDLE THE CONNECTION ERROR
// release the connection, and the data object
[connection release];
// receivedData is declared as a method instance elsewhere
[receivedData release];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// receivedData contains the data
// convert to string:
NSLog(#"finished loading: %#",[[[NSString alloc] initWithData:receivedData encoding:NSUTF8StringEncoding] autorelease]);
[connection release];
[receivedData release];
}
You'll want to expose the authentication functionality as a web service, then use the URL Loading code posted by Felix L. to initiate an actual connection to the web service.
You'll probably want to send a response from the server as XML, if so, you'll parse that response with an NSXMLParser, otherwise you can just send the response in whatever format you'd like and parse it appropriately.