I am trying to create something like a Network Manager using NSUrlConnections.
For that, I want to be able to send multiple requests, but I also want to be able to identify the client(delegate) that made the request when the response arrives.
I have created a NSDictionary like this:
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:SERVER_TIMEOUT];
....
[clients setObject:client forKey:connection];
in "- (void)connectionDidFinishLoading:(NSURLConnection *)connection" I have something like this:
client = (id<RTANetworkDelegate>)[clients objectForKey:connection];
[clients removeObjectForKey:connection];
The Network Manager is the delegate for all the connections, I do some preprocessing and then I send the (parsed) response to the right delegate, that sent the request in the first place.
Unfortunately, it appears that a NSMutableURLRequest cannot be set as a key in a dictionary since it does not have the copyWithZone method and I get the error:
-[NSURLConnection copyWithZone:]:
unrecognized selector sent to
instance
Any help would be much appreciated!
Thanks!
=======================================
[Edit] I already found this in the meantime:
http://blog.emmerinc.be/index.php/2009/03/15/multiple-async-nsurlconnections-example/
It seems to solve my problem.. I still don't know if it's the best solution though. I thought I would post it here since it might help others too.
You could use the -hash value of the connection object as the key:
[clients setObject:client forKey:[connection hash]];
I'd stay away from the actual URL or anything similar as two requests could potentially have the same URL.
Related
I'm currently working with a PHP developer to set up some server-side code, however, I'm not sure how to send the server API information to be stored in a database. He has asked me to send it in a url like this: exampleserver.com/register?deviceToken=[deviceToken]&otherstuff[otherStuff]. I have no problem with creating the URL string, my issue is actually doing something with it. I know this is a pretty stupid question, but I'm pretty new to Objective-C let alone communicating with servers! I have pulled information from servers using NSURLRequest and AFJSONRequestOperation before. Is it the same idea or are we no longer doing Requests? I've seen the word Post around a couple of times, but I'm unsure if this is what I'm after. Any help clearing this up would be really appreciated. Also, whatever the solution, I need it to be asynchronous!
Thanks for the help,
Regards,
Mike
This works for me:
NSURL *aURL = [NSURL URLWithString:#"http://www.google.co.uk/search?hl=en&q=hello%20world"];
NSURLRequest *aURLRequest = [NSURLRequest requestWithURL:aURL];
[NSURLConnection sendAsynchronousRequest:aURLRequest queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
NSLog(#"response=%#", response);
NSLog(#"data=%#", data);
NSLog(#"error=%#", error);
}];
The URL you show has data tacked onto the end of the URL, which is normally done with a http GET operation, the "normal" method. Just asking for the page at that URL is enough to send the data to the server. An http POST operation is typically used to send form data to a server, where the pairs like deviceToken=<deviceToken> are transferred in the body of the message rather than the URL. The advantage of that is typically that the body will be encrypted if the connection is https:, so the data stays secure. But for a simple insecure transaction, using a GET with the parameters in the URL is fine. There's a description of a POST transaction at iOS: how to perform a HTTP POST request?
NSURLRequest still works and is fine. If you want a more powerful library that handles post, get, put etc. and can work asynchronously and link directly to core data, I recommend RestKit (https://github.com/RestKit/RestKit).
For more on NSURL, see my answer here: NSURLConnection delegate method
I'm creating an iPhone app that consumes a json webservice. I have an NSURLRequest and NSURLConnection object that are used to load JSON data from that webservice:
NSMutableURLRequest *request = [[NSMutableURLRequest alloc]
initWithURL:url
cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
timeoutInterval:30];
[request setHTTPMethod: #"POST"];
//[request setHTTPShouldHandleCookies:YES];
//create connection
NSURLConnection *connection = [[NSURLConnection alloc]
initWithRequest:request delegate:self];
[connection start];
First time I executed the above code, using as the url "admin.mydomain.com/param1/value1/param2/value2", the response came through correctly (a JSON string: {"Wrong API Key"}).
I then changed the url to my staging server: "admin.stg.mydomain.com/param1/value1/param2/value2". This server provides me with some completely different output (when I try that new url in a browser, the correct output is shown, a json object completely different from what the first url gives me), but in my iphone app I still get the exact same response I got from the other server. If I try non existent urls I do get a correct error message.
It just seems to have cached the result from the original server and returns the same value for my stg subdomain, somehow matching the two urls (is this possible?), but I have cleared all caching data I could find. I have tried to clean the build and build directory, restarted xcode, the computer and everything, the cache policy is set to ignore the cache (see code). Important: I get the same behavior on my actual iPhone, not just the simulator.
Does anyone have any idea what could cause this kind of behavior? Am I forgetting something obvious?
I have been looking at this for hours on end now, any help is greatly appreciated!
I have changed the request method to 'GET', now I get the expected results! When checking the url in the browser a get request is used, when posting it I get a different response, which happens to be exactly the same as what I get on the dev server. Problem solved, just have to make some adjustments to the backend to allow a post request!
I am working in a iPhone project that uses restful web services. I need to send some tracking code or version number with every request sending from iPhone side. I am thinking of adding a header value into every request, by modifying a ASIHTTPRequest class.
Is there any method that ASIHTTPRequest providing to do this (without modifying framework files)?
If I need to modify ASIHTTPRequest class, what is the best place to modify it? (like buildRequestHeaders.. )
Thanks.
may be you can write a new class such as MyASIHttprequest and override the method requestwithURL
+ (MyASIHTTPrequest *) requestWithURL:url{
MyASIHTTPrequest *request;
if (request = [super requestWithUrl:url]){
[request addRequestHeader:#"" value:#""];
}
return request;
}
or you can write a method to add the header but maybe every time you new a asihttprequest, you should call this method to add header;
You can add headers by following method
ASIFormDataRequest *currentRequest = [ASIFormDataRequest requestWithURL:url];
[currentRequest addRequestHeader:#"" value:#""];
e.g.[currentRequest addRequestHeader:#"Content-Type" value:#"text/xml; charset=utf-8"];
Hope this helps.
If you are just starting by adding in ASIHTTPRequest and it is not embedded into your app yet then I recommend that you stop and switch to something else.
The creator of ASIHTTPRequest has discontinued development on the framework and even recommends in his blog post "Honestly, I think now is the time to start looking elsewhere." -Blog post
Also this was addressed in this question as well: Is it safe to still use ASIHTTPRequest?
I would personally recommend that you use NSURLConnection and send the data through the POST method.
I´ve just started using ASIHTTPRequest for iOs and I have a small issue with it. All requests are sent twice to the server even though I only get one reply from the library to my delegate methods.
Both sync and async requests have this issue. I use Xcode 4 with ARC but have disabled it for ASIHTTPRequest by adding -fno-objc-arc as compiler flags.
Any idea what´s wrong..?
Code:
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request startSynchronous];
NSError *error = [request error];
if (!error) {
}
This has bitten me too. I was using a GET request to validate a multi-use voucher code on a server. When we added a rate limitation for redeeming codes some customers reported hitting the limit before they should have. Turns out that some of the validations triggered two redeems.
Your request is using the GET method.
The default behavior when using GET is to allow persistent connections (the Keep-Alive HTTP header).
When using a persistent connection your GET request might get retransmitted if something on the network looks wonky (that's a technical term) instead of the request just failing. This is usually desirable because GET requests often do not have any side effects on the server.
POST or PUT requests on the other hand default to not use a persistent connection and will not retransmit your operation, which could well be a credit card purchase or something else with significant side effects.
If you wish to prevent your ASIHTTPRequest GET sometimes sending 2 or more server requests (due to network issues outside your control) you can simply set this flag:
request.shouldAttemptPersistentConnection = NO;
This should take care of the spurious GET duplicates on the server.
Thank you for your replies. I moved to the new MKNetworkKit and never looked back at ASIHttpRequest. https://github.com/MugunthKumar/MKNetworkKit
Øystein
It might be sending a HEAD request to fetch the response size followed by a GET request to actually get the content. See this section of the documentation for more information.
It could be because persistent connections are in use, so you're seeing a failed request on a old connection followed by a working request on a new connection. (GregInYEG is also correct that it could be a HEAD request.)
If you gather a network trace using a tool like wireshark or charlesproxy then it would be possible to see exactly what is happening.
I use ASIHttpRequest (v. 1.8-95) for Iphone and wanted to create a synchronous DELETE request together with some body data. I went this way:
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:nsUrl];
[request appendPostData:[#"some body params" dataUsingEncoding:NSUTF8StringEncoding]];
[request setRequestMethod:#"DELETE"];
[request startSynchronous];
Although I was confirmed on the client side via
NSLog(#"request: method:%#", request.requestMethod);
that the method was correctly set to "DELETE"
on the server side a "POST" request was received !
If I just omit
[request appendPostData: ..]
a correct DELETE is received on the server side)
So what's wrong with my request ?
Thanks for any solutions.
Regards
creator_11
Searching the asihttprequest group ( http://groups.google.com/group/asihttprequest/search?group=asihttprequest&q=delete&qt_g=Search+this+group ) turns up some relevant posts including a suggested workaround:
call buildPostBody on your request
after you've populated the body, but
before you set the request method.
HTTP verbs and usages can't just be mixed and matched. OK, they can, but you'd have to change the server to support your non-standard usage. DELETE should use the URI of the resource to be deleted, and thats it. No POST params, no attachment.
If really you want to send a little extra data along with the delete, you can set it in the headers of the request (addRequestHeader:value:), and server side pull that info out, but avoid that if you can. The reason is, the DELETE should be deleting one 'thing' referred to by it's URI. If the business logic of the server application says that delete should affect some other objects (eg cascading delete), the client application shouldn't know about that.
Can you explain what you're trying to POST while performing a DELETE, maybe I can offer an alternative solution.