0

Currently I'm still reading through some document and tutorial for NSTimer. From my current understanding, We call the timer and give it a method so that it will repeat itself. Then an idea struck me.(im working on other app proj)

What I plan to do

  • implement UIWebView
  • implement NSTimer(maybe 0.5sec) within the UIWebView with a method that check the UIWebView current url (absolutestring) and if it's not what I specified, it will redirect the url.

I have the code that I want to implement, the purpose is to rectify my knowledge on UIWebView and NSTimer and see if its plausible before I start working on it.( I'm still reading on documents. So would like to learn more and try out more before working on it)

The confusing part to me now is that, is my method compatible with NSTimer? Will it be plausible to use NSTimer within a UIWebView viewDidLoad method? Will there be a memory overload/crash due to the app constantly running the method every 0.5sec?

e.g of NSTimer (correct me if I'm wrong. But since I want it to be running forever as long as the user are in the UIWebView, I will only require this code set and not include NSRunLoop)

NSTimer *t = [NSTimer scheduledTimerWithTimeInterval: 2.0
                      target: self
                      selector:@selector(onTick:)
                      userInfo: nil repeats:NO];

-(void)onTick:(NSTimer *)timer {
   //do smth
}

EDIT2- @Robert Ryan, this is the code I'm using.(which work just now when i first changed to this) **(If i blocked out range2 section, then the error domain error-999 stopped. but the view still doesn't load)

     - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
    NSString *currentURL = [[request URL] absoluteString];
    NSRange range1= [currentURL rangeOfString:@"news"];
    NSRange range2= [currentURL rangeOfString:@"pdf"];
    if (range1.location == NSNotFound)
    {
        NSURL *url = [NSURL URLWithString:@"http://www.imc.jhmi.edu/news.html"];
        [webView loadRequest:[NSURLRequest requestWithURL:url]];

        return NO; //no to this if its not found.
    }
    if(range2.location==NSNotFound)
    {
        NSURL * url = [NSURL URLWithString:@"http://www.imc.jhmi.edu/news.html"];
        [webView loadRequest:[NSURLRequest requestWithURL:url]];
        return NO; //no to this if its not found
    }

    return YES; //everything else ok

}

EDIT3 - if i combine the both NSRange range1 and range2 into 1 statement then it work again(hopefully it will still work after an hour. xD)

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
    NSString *currentURL = [[request URL] absoluteString];
    NSRange range1= [currentURL rangeOfString:@"news"];
    NSRange range2= [currentURL rangeOfString:@"pdf"];
    if (range1.location == NSNotFound & range2.location==NSNotFound)
    {
        NSURL *url = [NSURL URLWithString:@"http://www.imc.jhmi.edu/news.html"];
        [webView loadRequest:[NSURLRequest requestWithURL:url]];

        return NO;
    }
return YES;
}
Yang Jie Domodomo
  • 685
  • 1
  • 8
  • 25
  • Probably not incompatible, but seems inefficient. Why would you want to do this? What problem are you trying to solve? Are you worried that the user will follow a link on your page that will take them away from the url in question? Or are you afraid the web page, itself, may do a redirect? Regardless, rather than doing a NSTimer (or any of the other ways to fire off a method in the future), wouldn't you be better with UIWebViewDelegate methods `webViewDidFinishLoad:` or `webView:shouldStartLoadWithRequest:navigationType:`? – Rob Jun 27 '12 at 06:29
  • Check these threads - http://stackoverflow.com/questions/605027/uiscrollview-pauses-nstimer-until-scrolling-finishes, http://stackoverflow.com/questions/6684016/why-timer-stops-when-scrolling-in-uiwebview-iphone – rishi Jun 27 '12 at 06:34
  • @RobertRyan - I tried `webView:shouldStartLoadWithRequest:navigationType:` but from what other ppl told me, it is only for the start(i assume it does not work after loading the page). What I want to solve is when people are in the view for awhile(lets say 5min), and they decided to go into other url, i would like to restrict them from going others beside those i specified. – Yang Jie Domodomo Jun 27 '12 at 07:14
  • No, it's not just for the initial load, but for all interaction through that UIWebView. It's designed precisely for what you are describing. Much, much better than polling with NSTimer or some other delayed method invocation. Try `webView:shouldStartLoadWithRequest:navigationType` out. I think you'll be happy. Just make sure you set your webview's delegate (otherwise you may not get the message). – Rob Jun 27 '12 at 07:18
  • I've set delegate. and im currently using that method, but it doesnt work out for me. I've posted the code im currently using with that method. If i enable/disable [webView reload] it just lash back, either everything or nothing load. – Yang Jie Domodomo Jun 27 '12 at 07:25
  • I don't think you can just change the URL and expect that to do anything. I would have thought you'd need to initiate a new request. So, I've added an answer that shows how you could redirect. – Rob Jun 27 '12 at 13:31

2 Answers2

2

If what you want is to make sure that the user does not navigate to other urls, you could add the following

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
    if ([[request.URL absoluteString] isEqualToString:@"http://YourAllowableURL1.com"]) {
        return YES;
    }

    if ([[request.URL absoluteString] isEqualToString:@"http://YourAllowableURL2.com"]) {
        return YES;
    }

    return NO;// user will not be able to go to any other urls
}

You can also specify a list of allowable URLs and make sure to return YES for only these URLs

Omar Abdelhafith
  • 21,163
  • 5
  • 52
  • 56
  • im currently using that method, but it doesnt work out for me. I've posted the code im currently using with that method. If i enable/disable [webView reload] it just lash back, either everything or nothing load. – Yang Jie Domodomo Jun 27 '12 at 07:25
1

The use of NSTimer's to determine an attempt to go to an "unapproved" web site is not quite what you want. The shouldStartLoadWithRequest will let you cancel the current request if the URL isn't acceptable. It does not, though, allow you to change the URL to effect a redirect. If you really want to redirect, you could initiate a brand new request, perhaps after a little delay, e.g.,

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
    NSString *currentURL = [[request URL] absoluteString];
    NSRange range = [currentURL rangeOfString:@"imc.jhmi.edu"];

    if (range.location == NSNotFound)
    {
        double delayInSeconds = 0.1;
        dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
        dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
            NSURL *url = [NSURL URLWithString:@"http://www.imc.jhmi.edu/news.html"];
            [webView loadRequest:[NSURLRequest requestWithURL:url]];
        });

        return NO;
    }

    return YES;
}

It actually looks like you don't have to wait, you can actually just initiate the new request immediately, but it doesn't seem right to do so before the previous shouldStartLoadWithRequest has completed. But if you wanted to do that, it obviously would be:

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
    NSString *currentURL = [[request URL] absoluteString];
    NSRange range = [currentURL rangeOfString:@"imc.jhmi.edu"];

    if (range.location == NSNotFound)
    {
        NSURL *url = [NSURL URLWithString:@"http://www.imc.jhmi.edu/news.html"];
        [webView loadRequest:[NSURLRequest requestWithURL:url]];

        return NO;
    }

    return YES;
}

Personally, I wouldn't redirect the user at all, but at most pop up a UIAlertView that tells them they have to stay on this site, but this is up to you:

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
    NSLog(@"%s %@", __FUNCTION__, request);

    NSString *currentURL = [[request URL] absoluteString];
    NSRange range = [currentURL rangeOfString:@"imc.jhmi.edu"];

    if (range.location == NSNotFound)
    {
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"This app only follows links within the www.imc.jhmi.edu site." 
                                                        message:nil 
                                                       delegate:nil 
                                              cancelButtonTitle:@"Ok" 
                                              otherButtonTitles:nil];
        [alert show];
        // [alert release]; // use in non-ARC
        return NO;
    }

    return YES;
}
Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • oh gee, loadRequest! why didn't I thought of using a different way to load it. Probably because I didn't replace the current absolute string with the new currentURL in my code thats why it still refresh to the same page.(I feel so stupid for not thinking of that possibility). and wow, now theres another new thing for me to read up on, dispatch_time section and using ^(void) (i assume to call a new method within a method) thanks a bunch! it works great now. – Yang Jie Domodomo Jun 28 '12 at 01:23
  • Ok, another problem has arise. I have no idea what happen(I never touch the code or anything after it work), but now when i launch the UIWebView, the screen just stay blank. – Yang Jie Domodomo Jun 28 '12 at 03:44
  • 1
    @YangJieDomodomo If you've really changed nothing, then that's curious. I'd try commenting out your `shouldStartLoadWithRequest` and see if it works (to make sure (a) there's not a bug in the algorithm; and (b) your initial load satisfies the rules in `shouldStartLoadWithRequest`. If it works after commenting out this routine, you know where your problem rests. If it still doesn't work, though, your problem rests in `viewDidLoad` or something about your view. Happy hunting! – Rob Jun 28 '12 at 04:03
  • I took out sholdstartload and it load the initial view. so viewdidload is fine. I tried using the error handling for web view and it return me error domain error -999. The funny part is the exact same code work just now but stop working now. – Yang Jie Domodomo Jun 28 '12 at 04:06
  • 1
    @YangJieDomodomo I didn't want to belabor the point, but your initial rendition of `shouldStartLoadWithRequest` listed in your updated question looks highly suspect; the logic doesn't look right. If you update your question with your latest rendition, I'm happy to take a look at it, but that version listed in your question doesn't seem like it could possibly work. – Rob Jun 28 '12 at 04:07
  • updated question. I tried removing my self added range2 portion and the error stop popping up, but view still not loading. – Yang Jie Domodomo Jun 28 '12 at 04:14
  • 1
    @YangJieDomodomo I think you have the return values reversed. If you're reloading the data, then `shouldStartLoadWithRequest` should return NO (i.e. you shouldn't let the original request go through because you're reloading it), but otherwise it should return YES (i.e. because everything is ok, the original request should be allowed to proceed). – Rob Jun 28 '12 at 04:39
  • It doesn't seems to like my second if statement. Once i taken out nsrange2, the startloadwithrequest will work, but if i put it in, blank page again. – Yang Jie Domodomo Jun 28 '12 at 06:04
  • Thanks for teaching me more about shouldStartLoadWithRequest. Looks like I had the wrong perception of it and how it work. Thanks for correcting it too. The code is now working like a charm(and hopefully permanent) after i combine both if statement into 1 statement. – Yang Jie Domodomo Jun 28 '12 at 06:11