Reputation: 1021
I'm having a very puzzling issue with NSURLConnection. It is returning the data in another thread or something, things are not working in the proper order. I'm supposed to receive the json data then parse it, but the data is actually being received after the parser fails. Here is the log.
2013-09-22 14:44:40.454 WebServiceExample[39306:a0b] Parsing Error: Error Domain=NSCocoaErrorDomain Code=3840 "The operation couldn’t be completed. (Cocoa error 3840.)" (No value.) UserInfo=0xa0b47e0 {NSDebugDescription=No value.} 2013-09-22 14:44:41.312 WebServiceExample[39306:a0b] Succeeded! Received 112 bytes of data
I'm making a small framework to ease my life to connect to rails API, I'm calling it objective rails OR, but I already spent the entire weekend trying to figure out what I'm doing wrong. Here's the code:
@interface ORObject : NSObject
@property (nonatomic, retain) NSMutableDictionary *properties;
@property (nonatomic, retain) ORWebManager *webManager;
@property (nonatomic, retain) NSString *route;
@property (nonatomic, retain) NSString *singularClassName;
- (id) initWithRoute:(NSString *) route webManager:(ORWebManager *) webManager;
- (id) initWithRoute:(NSString *) route;
- (ORObject *) find:(NSInteger) identifier;
@end
Here is the implementation of find:
- (ORObject *) find:(NSInteger) identifier
{
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%@/%@/%ld.%@", [ ORConfig sharedInstance].baseURL, self.route, (long)identifier, self.webManager. parser.contentType]];
ORObject *object = [self.webManager httpGet:url];
if (object) {
object.route = self.route;
object.webManager = self.webManager;
}
return object;
}
Here is the httpGet method of the ORWebManager class
- (ORObject *) httpGet:(NSURL *)url
{
ORGetRequester *requester = [[ORGetRequester alloc] init];
NSMutableData *data = [requester request:url];
return [self.parser toObject:data];
}
The superclass of ORGetRequester is ORHTTPRequester and it implements the NSURLConnectionDelegate protocol methods
@interface ORHTTPRequester : NSObject<NSURLConnectionDelegate>
@property (nonatomic, retain) NSMutableData *receivedData;
@property (nonatomic, retain) NSMutableURLRequest *req;
@property (nonatomic, retain) NSURLConnection *connection;
@end
@implementation ORHTTPRequester
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse
[self.receivedData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[self.receivedData appendData:data];
}
- (void)connection:(NSURLConnection *)connection
didFailWithError:(NSError *)error
{
NSLog(@"Connection failed! Error - %@ %@",
[error localizedDescription],
[[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(@"Succeeded! Received %d bytes of data",[self.receivedData length]);
}
@end
And finally here is ORGetRequester, this is where the "magic" happens.
@interface ORGetRequester : ORHTTPRequester
- (NSMutableData *) request:(NSURL *)url;
@end
@implementation ORGetRequester
- (NSMutableData *) request:(NSURL *)url
{
self.req = [NSMutableURLRequest requestWithURL:url
cachePolicy:NSURLRequestUseProtocolCachePol icy
timeoutInterval:60.0];
self.receivedData = [[NSMutableData alloc] init];
self.connection = [[NSURLConnection alloc] initWithRequest:self.req delegate:self];
if (!self.connection) {
NSLog(@"Connection Failed");
}
return self.receivedData;
}
@end
Upvotes: 0
Views: 128
Reputation: 112873
self.connection = [[NSURLConnection alloc] initWithRequest:self.req delegate:self];
returns immediately because it starts an async operation. You need to parse the data when connectionDidFinishLoading:
is called.
Or consider using:
+ (void)sendAsynchronousRequest:(NSURLRequest *)request queue:(NSOperationQueue *)queue completionHandler:(void (^)(NSURLResponse*, NSData*, NSError*))handler
The completion block will be called when the http operations is complete. Process the data in the completion block and notify any object that needs the data. This is probably a good bet if you do not need the other delegate methods.
Upvotes: 1