iPhone/objC
I'm really stuck here and I could use some help, please.
Let me first explain some things:
I have an UIWebView which loads an url. once the user clicks a link - (BOOL)webView:shouldStartLoadWithRequest:
navigationType: gets a message (according to the protocol). Inside this method I can decide if the url should be loaded in the webView or to do something else with it. I'm establishing an NSURLConnection so I can examine the response.
- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request
navigationType:(UIWebViewNavigationType)navigationType {
NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
if (theConnection) {
NSLog(@" Connection established");
receivedDataFromConnection = [[NSMutableData data] retain];
}
else {
NSLog(@"Connection failed");
}
if (downloadYESorNO == YES) {
NSLog(@"Do the download");
return NO;
}
else {
NSLog(@"will show in webView");
return YES;
}
}
once the app gets an response - (void)connection:didReceiveResponse: gets an message (according to protocol) and I can analyze the response there.
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
NSString *MIME = response.MIMEType;
NSString *appDirectory = [[NSBundle mainBundle] bundlePath];
NSString *pathMIMETYPESplist = [appDirectory stringByAppendingPathComponent:@"MIMETYPES.plist"];
NSArray *displayMIMETypes = [NSArray arrayWithContentsOfFile: pathMIMETYPESplist];
BOOL *asdf = [displayMIMETypes containsObject:MIME];
if (asdf == YES) {
downloadYESorNO =NO;
}
else {
downloadYESorNO = YES;
}
[receivedDataFromConnection setLength:0];
[connection release];
Now what I'm trying to achieve is to let - (BOOL)webView:shouldStartLoadWithRequest: wait till -(void)connection:didReceiveResponse: is ready.
I can work with sendSynchronousRequest: cause then it would download the complete file before I can examine the response.
Does anyone have an idea? Thanks in advance.
or is there a better way to examine the response?
If you really want - (BOOL)webView:shouldStartLoadWithRequest: you have two options. The first is that you can synchronously load your data:
NSData * receivedDataFromConnection = [NSURLConnection sendSynchronousRequest: request returningResponse:&response error:&error];
If you do that you don't have to implement the delegate methods (as they won't be called). You would then just pass the response into a method that checks whether or not you want to download.
The downside to that is you are going to game the runloop while you are loading if you do that, which means the UI will become unresponsive, and if you are on a slow connection the app might get killed because it will stop responding to events for too long.
The other option is to run your runLoop inside of the webView:shouldStartLoadWithRequest: navigationType:
- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request
navigationType:(UIWebViewNavigationType)navigationType {
NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
if (theConnection) {
NSLog(@" Connection established");
receivedDataFromConnection = [[NSMutableData data] retain];
}
else {
NSLog(@"Connection failed");
}
waitingForResponse = YES;
while (waitingForResponse) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
[pool drain];
}
if (downloadYESorNO == YES) {
NSLog(@"Do the download");
return NO;
}
else {
NSLog(@"will show in webView");
return YES;
}
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
NSString *MIME = response.MIMEType;
NSString *appDirectory = [[NSBundle mainBundle] bundlePath];
NSString *pathMIMETYPESplist = [appDirectory stringByAppendingPathComponent:@"MIMETYPES.plist"];
NSArray *displayMIMETypes = [NSArray arrayWithContentsOfFile: pathMIMETYPESplist];
BOOL *asdf = [displayMIMETypes containsObject:MIME];
if (asdf == YES) {
downloadYESorNO =NO;
} else {
downloadYESorNO = YES;
}
[receivedDataFromConnection setLength:0];
[connection release];
waitingForResponse = NO;
}
By executing the runloop you allow event processing to continue, which lets your delegate methods get called. Clearly you need to detect when it is done and stop running the runloop, which is what the waitingForResponse ivar is for.
Because your runloop is running the UI will not only still be capable of responding to event, but completely interactive. That means the user could tap on more links while you are doing this. You will need to protect yourself from that, either by making your code reentrant, or by disabling user interaction for anything that will cause problems.
Either way around there are a lot of gotchas to either approach. This is really a somewhat complicated thing, and if you are not an experienced Cocoa developer I don't recommend doing it, if you can find some other way of handling your download process it will be a lot simpler.