I want to POST 3 requests within same class with XML parser. I can manage to do only one request at a time. When I POST multiple requests, it says Parser Error. This is how I tried.
NSURL *url = [[NSURL alloc] initWithString:getAllFoodsURL];
NSMutableURLRequest *req = [[NSMutableURLRequest alloc] initWithURL:url];
NSString *paramDataString = [NSString stringWithString:
#"<GetNames><DeviceId>1234</DeviceId><UserId>200</UserId></GetNames>"];
[req addValue:#"application/xml" forHTTPHeaderField:#"content-type"];
[req setHTTPMethod:#"POST"];
NSData *paramData = [paramDataString dataUsingEncoding:NSUTF8StringEncoding];
[req setHTTPBody: paramData];
NSURLConnection *theConnection=[[NSURLConnection alloc]initWithRequest:req delegate:self];
if (theConnection) {
NSMutableData *data = [[NSMutableData alloc] init];
self.receivedData=data;
[data release];
}
I have used NSXMLParser delegates methods. After one request is completed(connection release), then I create another connection and do the same process for second request.
But it doesnot work.
I want to know, how to manage multiple requests with NSXMLParser?
If you can give me a code example, its highly appreciated.
I guess NSThread is what you are looking for.
But I am not sure as I am not much aware about that.
Note that NSXMLParser isn't involved in HTTP requests -- do you mean NSURLRequest instead? You'll need to make your requests separately, possibly using separate blocks, operations, or threads.
Once you've retrieved the data for each request, you'll need to use separate NSXMLParser objects for each. A single instance of NSXMLParser is tied to its XML data at initialization -- you can't reuse a parser. You can use the same delegate for all your xml parsers, and the delegate can use the first parameter to each of the xml parser delegate methods (i.e. parser) to know which parser is calling a given method.
Related
I have the following code in objective c that is supposed to make a GET http request to my website which in turn will submit something into my MySQL database...
NSMutableURLRequest *request =[NSMutableURLRequest requestWithURL:[NSURL URLWithString:#"http://www.website.com/VideoPush/plist/urlTransfer.php"]];
[request setHTTPMethod:#"GET"];
NSString *post =[[NSString alloc] initWithFormat:#"videoID=%#",videoURL];
[request setHTTPBody:[post dataUsingEncoding:NSUTF8StringEncoding]];
Note: I'm a total beginner to http requests with Objective c so I realize I could be missing something obvious...
Now if I run the following url in my browser...
http://www.website.com/VideoPush/plist/urlTransfer.php?videoID=hhklskdjsad
Then something gets entered into the database, but not when I'm using objective c. Also what is the difference between GET and POST when you make requests like this (since the user doesn't see the url anyways)?
ALSO: Am I allowed to pass a url (still a nsstring with /'s though) as the videoURL variable above
You've tried to set the body of a GET request, which makes no sense. What you probably want is:
NSString *urlString = [NSString stringWithFormat:#"http://www.website.com/VideoPush/plist/urlTransfer.php?videoID=%#", videoURL];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlString]];
... the rest of your method ...
You should probably go and have a read up about what a GET and a POST is and why I said it makes no sense to have a body in a GET request.
ALSO: Am I allowed to pass a url (still a nsstring with /'s though) as the videoURL variable above
No, you will need to URL encode anything in the query string. You can use CFURLCreateStringByAddingPercentEscapes to do this for you.
How to upload NSData Object to server with specific name ?
NSData *imgData; // Image Data
NSString *imgName = #"myfile.png";
I want to upload data to server with specific file name.
1. Upload Data (imgData)
2. To server (my_server.com/upload.html)
3. With file name (imgName)
I am currently working on a school project where I needed to do something similar to this...
I was placing longitude and latitude values in a database.
MAKE NOTE THAT THERE MAY BE MUCH SIMPLER WAYS TO DO THIS. I AM BY NO MEANS A "PRO" AT OBJECTIVE-C PROGRAMMING
There are going to be three things you need.
a server in which you have access to.
a PHP file that will write the data to the database.
an NSURLConnection object;
I had placed the following code in one of the delegate methods for CLLocationManager.
The NSURLConnection object should look something like this:
//this is where I put the url for my PHP file
url = [[NSURL alloc] initWithString:[NSString stringWithFormat:#"http://www.example.com/folder/example.php"]];
urlRequest = [NSURLRequest requestWithURL:url];
connection = [[NSURLConnection alloc] initWithRequest:urlRequest delegate:self];
Of course the variables: url, urlRequest, and connection are declared in the header file like this
NSURL *url;
NSURLRequest *urlRequest;
NSMutableData *filedata;
NSURLConnection *connection;
I am trying to access a Drupal service that takes more than one argument. The method is views.get and the server I'm using is REST 6.x-2.0-beta3. I am retrieving data from the server for 0 or 1 arguments with no trouble. Any argument after the first, however, is simply ignored. I have tested the view on the Drupal site, and it limits results correctly for every argument passed.
I've come to the conclusion that my problem must be the formatting, but I've tried nearly everything I can think of, not to mention a dozen suggestions I've found while Googling for an answer. My code is below:
responseData = [[NSMutableData data] retain];
NSMutableString *httpBodyString =[[NSMutableString alloc] initWithString:#"method=views.get&view_name=apps&args=1&display_id=default"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:#"http://drupalserver.com/services/rest/service_views/get.json"]];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:[httpBodyString dataUsingEncoding:NSUTF8StringEncoding]];
[httpBodyString release];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
I have tried:
args=1,2
args=[1,2]
args="1,2"
args=["1","2"]
and several others along that vein. Does anyone know the proper way to do this?
You should considering using, https://github.com/workhabitinc/drupal-ios-sdk
I have a method that I call to make web service requests using GET. It looks like this:
- (UIImage*)getImageWithSeriesGUID:(NSString*)seriesGUID ImageID:(int)imageID {
NSString * unescapedString = RIVERWOODS_GET_IMAGE(seriesGUID, imageID);
NSURL *url = [[NSURL alloc] initWithString:[unescapedString stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding]];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setRequestMethod:#"GET"];
[request addRequestHeader:#"Connection" value:#"Keep-Alive"];
[request startSynchronous];
NSError *error = [request error];
if (!error) {
NSData *response = [request responseData];
//NSLog(#"Size: %#",[response length]);
NSString *content = [[[NSString alloc] initWithData:response
encoding:NSUTF8StringEncoding] autorelease];
NSLog(#"Data: %#", content);
UIImage *image = [UIImage imageWithData:response];
return image;
}
return nil;
}
This approach works ok, but it is just REALLY slowly. On the other end I am iterating through a for loop so this method gets called 20 times if the picture array I need to collect has 20 images. I am looking to improve the efficiency of this process, and I am thinking that I should be able to iterate through all the image Id's I need to collect right here in this method.
It seems to me that the reason this goes so slowly is because the multiple requests that we keep opening and closing. THe images I am pulling in are on average ~15kb.
My question: What can I do to change this method around to make it so I can improve efficiency and take advantage of the HTTP keep-alive features? I am thinking that instead of passing in an image ID, I can just pass in the count of the array I need to make, and then setup a for-loop of some sorts here in the request method which would then allow me to pass back an array of images...
Is that the way to go? Is there something I am missing? I appreciate your help and input!!
The reason why this is slow as hell is that you're doing the requests synchronously (which is always a no-no anyway), one-by-one. You need to refactor your download method to work asynchronously, and concurrently.
My approach to requesting data on the wire in that manner is as follows:
Create a global network connection 'controller' (accessible from your App Delegate), which can create an ASINetworkQueue on the fly when required and release it when no requests remain
Wrap your requests into a subclass of ASIHTTPRequest, and override the done/fail methods in those subclasses (make them fire a notification with returned data if you like; or write to disk and update a db with their reference).
For every request, grab the queue reference, and add your request to the queue.
The queue will grow and shrink as needed
If I were at my computer I'd check into github an example of this, but really the only difficult part is the global connection manager, and the ASI* guys have written a great example here on gist.github. Also, a better explanation of the above (where I learnt it from) is here.
I connect asynchronously with server each 5 seconds. The URL is the same, but POST-body is changed each time. Now I create NSURL, NSURLRequest and NSURLConnection from the scratch each time.
I think it'd be more effective to set connection once and just use that one further.
I am a newbie and not sure if that possible. There is no mutable NSURLConnection, but may it's need to create NSURLConnection like:
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL: url];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
and change NSMutableURLRequest POST-data to send another request to server.
Which way is right?
I assume what you're concerned about is the overhead of creating the HTTP connection. NSURLConnection is smart enough to handle this for you using HTTP/1.1 and reusing existing connections. It does not use pipelining last time I checked, but for your purpose, connection reuse should be sufficient. I do encourage you to put a network sniffer on this and make sure that it's working as you want them to.
The cost of creating the objects themselves is trivial on the order of once per 5s and you shouldn't try to optimize that (though of course you should reuse the NSURL). It's the opening a connection to the server that's expensive, especially on iPhone.
If you find you really do need pipelining, you unfortunately will have to roll your own. I've heard that CFHTTPStream can do it, but I don't see a lot of evidence of that. CocoaAsyncSocket is your best bet for low-level access to the sockets without having to write low-level code.
Since latency on the cell network can be very bad, it's possible that your connection will take longer than 5s to complete. Do make sure that one connection is done before starting the next, or you'll start making more and more open connections.
Just to clarify things, NSURLConnection will reuse existing sockets, but only for a relatively small time frame (12 seconds). If you send a request, get back a response, and send a subsequent request within 12 seconds that 2nd request will got out on the same socket. Otherwise the socket will be closed by the client. A bug has been filed with Apple to increase this timer or to make it configurable.
#Rob Napier #Eric Nelson
As you mentioned: "NSURLConnection is smart enough to handle this for you using HTTP/1.1 and reusing existing connections".
However, I can not find such description in any Apple's document about that.
To make thing clear, I write some code to test it:
- (IBAction)onClickSend:(id)sender {
[self sendOneRequest];
}
-(void)sendOneRequest {
NSURL *url = [NSURL URLWithString:#"http://192.168.1.100:1234"];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
[request setHTTPMethod:#"POST"];
[request addValue:[Base64 encodeFromString:kValueVersion] forHTTPHeaderField:kKeyVersion];
[request addValue:[Base64 encodeFromString:kValueDataTypeCmd] forHTTPHeaderField:kKeyDataType];
[request addValue:[Base64 encodeFromString:#"Test"] forHTTPHeaderField:kKeyCmdName];
[request addValue:[Base64 encodeFromString:#"Test"] forHTTPHeaderField:kKeyDeviceName];
[request addValue:[Base64 encodeFromString:#"xxdafadfadfa"] forHTTPHeaderField:kKeyDTLCookies];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection start];
}
And then, I start wireshark to catch packages on the server(192.168.1.xxx), using "(tcp.flags.syn==1 ) || (tcp.flags == 0x0010 && tcp.seq==1 && tcp.ack==1)" to filter tcp 3-way hand shake. Unfortunately, I can see the 3-way hand shake for each calling of "sendOneRequest". Which means, the NSURLConnection seems not reuse the existing connections. Can some one point out what's wrong in my code and how to send multiple requests via one socket connection by NSURLConnection?
I also tried synchronous way to send request:
-(void)sendOneRequest {
NSURL *url = [NSURL URLWithString:#"http://192.168.1.100:1234"];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
[request setHTTPMethod:#"POST"];
[request addValue:[Base64 encodeFromString:kValueVersion] forHTTPHeaderField:kKeyVersion];
[request addValue:[Base64 encodeFromString:kValueDataTypeCmd] forHTTPHeaderField:kKeyDataType];
[request addValue:[Base64 encodeFromString:#"Test"] forHTTPHeaderField:kKeyCmdName];
[request addValue:[Base64 encodeFromString:#"Test"] forHTTPHeaderField:kKeyDeviceName];
[request addValue:[Base64 encodeFromString:#"xxdafadfadfa"] forHTTPHeaderField:kKeyDTLCookies];
[NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
sleep(1);
[NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
sleep(1);
[NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
}
And the result is the same.
=======UPDATE============================
Finally, I found the reason why my test is different from Rob and Eric say.
In short, Rob and Eric are correct. And NSURLConnection uses “keep-alive” as default for using HTTP/1.1 and reuses existing socket connection, but only for a relatively small time frame.
However, NSURLConnection has some problems for “chunked transfer-coding”(ie. without content-length).
In my test, server side send a response without content-length and response data, and it's chunked response and NSURLConnection will close the connection, thus 3-way hand shake occurs for each http post.
I changed my server code, set the length of response as 0, and the behavior is correct.
make a method that returns a request and do
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:[self requestMethod] delegate:self];
?