Riddle me this: I am using a NSURLConnection on an iPhone Simulator SDK 3.1.2 object to issue multiple sequential (not concurrent) https requests. Everything works fine 95% of the time, but every so often (maybe around 50-100 requests) I get the situation where the delegate method
- (void)connectionDidFinishLoading:(NSURLConnection *)connection;
is called after [connection start], but without any call to the delegate method
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
I have reduced the problem down to the source below. From what I understand this breaks the contract of NSURLConnection's defined behaviour. Has anyone else had this problem, and is it a known bug or am I using NSURLConnection wrong?
static BOOL hasSeenResponse = NO;
//Create a NSURLConnection and start it
-(void) begin {
NSURL* url = [NSURL URLWithString#"https://some.domain.com/some/path/?some=query"];
[[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookieAcceptPolicy:NSHTTPCookieAcceptPolicyNever];
NSURLRequest* request = [NSURLRequest requestWithURL:url];
if ([NSURLConnection canHandleRequest:request]) {
NSURLConnection* connection = [[NSURLConnection connectionWithRequest:request delegate:self] retain];
hasSeenResponse = NO;
[connection start];
}
}
#pragma mark NSURLConnection Delegate Methods
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
if (!hasSeenResponse) {
NSLog(#"\n\nNo Response Recieved\n");
}
[connection release];
[self begin];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
[connection release];
[self begin];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
hasSeenResponse = YES;
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
}
I was able to fix the problem by adding the delegate for re-directs which always accepts
-(NSURLRequest *)connection:(NSURLConnection *)connection
willSendRequest:(NSURLRequest *)request
redirectResponse:(NSURLResponse *)redirectResponse
{
return request;
}
As I understand it, this is the default behavior so I do not know why this solves the problem.
The URL I was sending the request to, did issue a re-direct, but that also does not explain why the HTTP request worked the other ~95% of the time.
I hope this helps someone with a similar problem in the future.
Related
(in MAC OSX- Xcode) I tried to read file by FTP using NSURLConnection class, it is work fine just if my code in main Application Delegate class (AppDelegate) but if i using it outside (another .h .m files) the connection delegate not called.
Any help!?
here is my code:
-(void)getURL {
NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:#"ftp://.... connection string with file"]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
NSURLConnection *connection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if (connection) {
// Do something
} else {
// Inform the user that the connection failed.
NSLog(#"connection failed");
}
}
Delegates:
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
NSLog(#"didReceiveResponse");
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(#"connectionDidFinishLoading");
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
//Getting file data
[receivedData appendData:data];
}
Did you add the delegate <NSURLConnectionDelegate> to the view controller you are trying to use it in ?
for example
#interface ViewController : UIViewController <NSURLConnectionDelegate>
I am making call to a server requesting JSON data using NSURLConnection.
For some reason I get part of the response. If I hit the url through the browser the response its correct. The weird thing is that it happens only sometime. So I'm having a hard time debugging the issue.
Then when because the response is not complete I get the following error:
Error Domain=NSCocoaErrorDomain Code=3840 "The operation couldn’t be completed. (Cocoa error 3840.)" (Invalid value around character 0.) UserInfo=0xa4634a0 {NSDebugDescription=Invalid value around character 0.} {
NSDebugDescription = "Invalid value around character 0.";
}
I guess it could also be an issue with the server it self. Here's my code:
-(void) getShareHistory:(NSString *)range paging:(NSInteger *)page{
NSString *post = [NSString stringWithFormat:#"range=%#&paging=%#",
range,
[NSString stringWithFormat:#"%ld",(long)page]];
NSString *url = [NSString stringWithFormat:#"http://www/domai.com/handle_share_links.php?action=history"];
NSData *post_data = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:#"%d", [post_data length]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setCachePolicy:NSURLRequestUseProtocolCachePolicy];
[request setURL:[NSURL URLWithString:url]];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:post_data];
self.shareHistoryConn = [[NSURLConnection alloc] initWithRequest:request delegate:self];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)response{
NSString *strData = [[NSString alloc]initWithData:response encoding:NSASCIIStringEncoding];
NSLog(#"response %#",strData);
NSError *jsonParsingError = nil;
if(connection == self.shareHistoryConn)
{
NSArray *data = [NSJSONSerialization JSONObjectWithData:response options:NSJSONReadingAllowFragments error:&jsonParsingError];
if(!jsonParsingError)
{
[[self delegate] onGetShareHistorySuccess:data];
}else{
[[self delegate] onGetShareHistoryFailed:jsonParsingError];
}
}
Thanks in advance.
What you're seeing is normal behavior. didReceiveData can be called any number of times. It is up to you to keep accumulating the data until you get connectionDidFinishLoading.
The standard delegate structure is like this:
- (void) connection:(NSURLConnection *)connection
didReceiveResponse:(NSURLResponse *)response {
// connection is starting, clear buffer
[self.receivedData setLength:0];
}
- (void) connection:(NSURLConnection *)connection
didReceiveData:(NSData *)data {
// data is arriving, add it to the buffer
[self.receivedData appendData:data];
}
- (void)connection:(NSURLConnection*)connection
didFailWithError:(NSError *)error {
// something went wrong, clean up interface as needed
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// all done, we are ready to rock and roll
// do something with self.receivedData
}
Always implement all four delegate methods.
I've done exactly what this official documentation instructed. I created a console project for testing purpose. And then I created a class called RequestSender (see code below) and I made an instance of this class in the main function.
RequestSender.h:
#import <Foundation/Foundation.h>
#interface RequestSender : NSObject <NSURLConnectionDelegate> {
NSMutableData* d;
}
#end
RequestSender.m:
#import "RequestSender.h"
#implementation RequestSender
- (id)init {
self = [super init];
if (self) {
NSString* s = #"http://www.apple.com/";
NSURL* u = [[NSURL alloc] initWithString:s];
NSURLRequest* r = [[NSURLRequest alloc] initWithURL:u];
NSURLConnection* c = [[NSURLConnection alloc] initWithRequest:r delegate:self];
if (c) {
d = [NSMutableData data];
}
return self;
} else {
return nil;
}
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[d setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[d appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
}
#end
This will no doubt be executed in the main thread and default run loop. However non of the delegation methods are called.
I've done a lot of testing and read many posts but I still don't have a clue.
Please help me. This is driving me mad.
Thanx!
I believe you're missing the part where you start the connection. The connection class offers another method for this, or you could just call it off of your "c" object.
NSURLConnection* c = [[NSURLConnection alloc] initWithRequest:r delegate:self];
if (c) {
d = [NSMutableData data];
[c start];
}
or
NSURLConnection* c = [[NSURLConnection alloc] initWithRequest:r delegate:self startImmediately:YES];
if (c) {
d = [NSMutableData data];
}
When trying to compile an infinite while loop in xcode iphone view based application, it gives me an error that reads expected identifier or '(' before 'while'. I made it as simple as possible. Sorry about the picture. Code block was not working. If you want to see an image of the code, here is the link. http://www.freeimagehosting.net/uploads/931d5d8788.gif
#import "Lockerz_NotifierViewController.h"
#implementation Lockerz_NotifierViewController
NSMutableData *responseData;
while (1) {
NSURLRequest *theRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://amicionline.me"]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
// create a connection
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if(theConnection) {
// create the datum
responseData=[[NSMutableData data] retain];
} else {
// code this later
}
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[responseData setLength:0];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// make it work
NSLog(#"Succeeded! Received %d bytes of data:",[responseData length]);
// release it
[connection release];
[responseData release];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[responseData appendData:data];
}
What are you trying to do? You can't write code directly in an #implementation. You must put it inside a method, for example:
-(void)start {
while (1) {
...
}
}
I have the following delegate method of NSURLConnection
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(#"DONE, Receive bytes: %d", [webData length]);
NSString *theXML = [[NSString alloc]initWithBytes:[webData mutableBytes] length:[webData length] encoding:NSUTF8StringEncoding];
//NSLog(theXML);
[theXML release];
if(xmlParser)
{
[xmlParser release];
}
else
{
xmlParser = [[NSXMLParser alloc]initWithData:webData];
[xmlParser setDelegate:self];
[xmlParser setShouldResolveExternalEntities:YES];
[xmlParser parse];
[connection release];
[webData release];
NSLog(#"\n\n\n\n");
NSLog(httpResult);
}
I want to return httpResult - how do i do this? I have the above method in a class. I create an instance of this class in another controller class which calls a function to create an http request. This function then in turn calls this delegate method. How do i return httpResult to the controller class?
I have figured it out - thanks guys
Give that class either a delegate or a didFinish-type callback and set that to tell your controller when it's done.