0

I'm posting to a RESTful webservice and receiving a response, this works great if I'm getting back only a few records however there is a threshold where didReceiveData: stops being called (6 records) and it just hangs. (does not matter what records, just the number)

I can't seem to figure out why. I'm getting a status message of 200 application/json in didReceiveResponse: however that's the last I hear from my connection.

From other clients I can get the full data with any number of records so it's related to my NSURLConnection code.

See full NSURLConnection Post class below.

the .h

#import <Foundation/Foundation.h>
#import "MBProgressHUD.h"

@protocol PostJsonDelegate <NSObject, NSURLConnectionDelegate>
@optional
- (void) downloadFinished;
- (void) downloadReceivedData;
- (void) dataDownloadFailed: (NSString *) reason;
@end

@interface PostURLJson : NSObject {
    NSMutableData *receivedData;
    int expectedLength;
    MBProgressHUD *HUD;
}

@property (strong, nonatomic) NSMutableData *receivedData;
@property (weak) id <PostJsonDelegate> delegate;
@property (assign, nonatomic) int expectedLength;

+ (id)initWithURL:(NSString *)url dictionary:(NSDictionary *)dictionary withDelegate:(id <PostJsonDelegate>)delegate;

@end

the .m

#import "PostURLJson.h"
#define SAFE_PERFORM_WITH_ARG(THE_OBJECT, THE_SELECTOR, THE_ARG) (([THE_OBJECT respondsToSelector:THE_SELECTOR]) ? [THE_OBJECT performSelector:THE_SELECTOR withObject:THE_ARG] : nil)

@implementation PostURLJson

@synthesize delegate;

@synthesize receivedData;
@synthesize expectedLength;

+ (id)initWithURL:(NSString *)url dictionary:(NSDictionary *)dictionary withDelegate:(id <PostJsonDelegate>)delegate
{    
    if (!url)
    {
        NSLog(@"Error. No URL");
        return nil;
    }

    PostURLJson *postJson = [[self alloc] init];
    postJson.delegate = delegate;

    [postJson loadWithURL:url dictionary:dictionary];

    return postJson;
}

- (void)loadWithURL:(NSString *)url dictionary:(NSDictionary *)dictionary 
{
    [self setExpectedLength:0];

    receivedData = [[NSMutableData alloc] init];

    NSError* error;

    NSDictionary *tmp = [[NSDictionary alloc] initWithDictionary:dictionary];

    NSData *postdata = [NSJSONSerialization dataWithJSONObject:tmp options:0 error:&error];

    NSString *someString = [[NSString alloc] initWithData:postdata encoding:NSASCIIStringEncoding];
    NSLog(@"%@",someString);

    NSString *postLength = [NSString stringWithFormat:@"%d", [postdata length]];

    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
    [request setURL:[NSURL URLWithString:url]];
    [request setHTTPMethod:@"POST"];
    [request setTimeoutInterval:10.0f];

    [request setValue:postLength forHTTPHeaderField:@"Content-Length"];
    [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
    [request setHTTPBody:postdata];

    NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:self];
    [connection start];
    [self setLoadingModeEnabled:YES];
}

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
    NSHTTPURLResponse * httpResponse = (NSHTTPURLResponse *) response;
    int errorCode = httpResponse.statusCode;
    NSString *fileMIMEType = [[httpResponse MIMEType] lowercaseString];

    NSLog(@"%d",errorCode);
    NSLog(@"%@",fileMIMEType);

    [receivedData setLength:0];

    // Check for bad connection
    expectedLength = [response expectedContentLength];
    if (expectedLength == NSURLResponseUnknownLength)
    {
        NSString *reason = [NSString stringWithFormat:@"Invalid URL"];
        SAFE_PERFORM_WITH_ARG(delegate, @selector(dataDownloadFailed:), reason);
        [connection cancel];
        return;
    }
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    [receivedData appendData:data];
    SAFE_PERFORM_WITH_ARG(delegate, @selector(downloadReceivedData), nil);
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    SAFE_PERFORM_WITH_ARG(delegate, @selector(downloadFinished), nil);
    [self setLoadingModeEnabled:NO];
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    NSLog(@"Something went wrong...");
    HUD.labelText = @"Something went wrong...";
    [self performSelector:@selector(didFailHideHud) withObject:nil afterDelay:2];
}

- (void)setLoadingModeEnabled:(BOOL)isLoading
{
    //when network action, toggle network indicator and activity indicator
    if (isLoading) {
        [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;

        UIWindow *window = [UIApplication sharedApplication].keyWindow;
        HUD = [[MBProgressHUD alloc] initWithWindow:window];
        [window addSubview:HUD];
        HUD.labelText = @"Loading";
        [HUD show:YES];
    } else {
        [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;

        [HUD hide:YES];
        [HUD removeFromSuperview];
    }

}

-(void)didFailHideHud
{
    [HUD hide:YES];
    [HUD removeFromSuperview];
}

@end

Edit Server was not giving back a valid length after a certain size triggering NSURLResponseUnknownLength which I had mistakenly not logged so I was not getting my "Invalid URL" message in the console.

if (expectedLength == NSURLResponseUnknownLength)
    {
        NSString *reason = [NSString stringWithFormat:@"Invalid URL"];
        SAFE_PERFORM_WITH_ARG(delegate, @selector(dataDownloadFailed:), reason);
        [connection cancel];
        return;
    }
KDM
  • 197
  • 5
  • 18
  • a typical Timeout Interval is around 60 seconds, what happens when you increase yours? – Jesse Gumpo Jul 10 '12 at 15:33
  • Same thing, actually I set such a short timeout to try and debug this issue. – KDM Jul 10 '12 at 15:38
  • Do you reach connectionDidFinishLoading or didFailWithError ? – Aymarick Jul 10 '12 at 15:58
  • Figured it out! I was not logging my *reason @"invalid URL". So it was exiting correctly because of the content length being an unknown length. I commented out that code and it does load the full connection and receive the data! it's just that for some reason the length gets messed up from the server when there is more then 6 records. – KDM Jul 10 '12 at 16:13

1 Answers1

0

Try this:

NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self  startImmediately:NO];
[connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
[connection start];

Because if you run the connection in the NSDefaultRunLoopMode and there is UITableView scrolling, it will hang the connection delegate.

However your problem is different. Some servers will limit the number of simultaneous connections from a single client. If you are in the case, then the first connections would succeed and the others would hang until previous connections complete.

hrchen
  • 1,223
  • 13
  • 17