0

I have one view controller (let's call it ViewController) with timer within its code, and have another view controller (let's call it ContentViewController) with webView within it which shows content depending on which button is clicked.

I have buttons on ViewController which, when clicked, pushes ContentViewController which loads a html file into its webView.

Timers are used to close ContentViewController if it is pushed.

Here's how I create timers:

-(void)createTimer :(NSNumber*)index
{
if (_show)
{
    NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:index, @"parameter1", nil];
    switch ([index intValue])
    {
        case 1001:
            [NSTimer scheduledTimerWithTimeInterval:10.0 target:self selector:@selector(updateUi:) userInfo:dictionary repeats:YES];
            break;
        case 1002:
            [NSTimer scheduledTimerWithTimeInterval:10.0 target:self selector:@selector(updateUi:) userInfo:dictionary repeats:YES];
            break;
        case 1003:
            [NSTimer scheduledTimerWithTimeInterval:20.0 target:self selector:@selector(updateUi:) userInfo:dictionary repeats:YES];
            break;
        case 1004:
            [NSTimer scheduledTimerWithTimeInterval:20.0 target:self selector:@selector(updateUi:) userInfo:dictionary repeats:YES];
            break;
    }
}
}

Here's the code in ViewController which closes ContentViewController when timer fired:

-(void)updateUi :(NSTimer *)timer
{
int  index = [[timer.userInfo objectForKey:@"parameter1"] intValue];

if([self.navigationController.visibleViewController isKindOfClass:[ContentViewController class]])
{
    if ([[[NSUserDefaults standardUserDefaults]valueForKey:@"CurrentString"] intValue]==index )
    {
        [self.navigationController popViewControllerAnimated:YES];
    }
}
}

And on web page which is shown on ContentViewController there's a button,when user clicks it ContentView must go back to ViewController. Here's how I do this:

- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType
{
NSURL *URL = [request URL];
if ([[URL scheme] isEqualToString:@"coffee-drink"])
{
    NSString *urlString = [[request URL] absoluteString];
    NSArray *urlParts = [urlString componentsSeparatedByString:@":"];

    if (urlParts.count > 1)                          ///------------поменял
    {
        [self.navigationController popViewControllerAnimated:YES];
    }
}

return YES;
}    

All of above works fine but sometimes it crashes with the following error:

[ContentViewController respondsToSelector:]: message sent to deallocated instance

And also, I have other errors like these:

nested push animation can result in corrupted navigation bar

Finishing up a navigation transition in an unexpected state. Navigation Bar subview tree might get corrupted.

and

delegate (webView:decidePolicyForNavigationAction:request:frame:decisionListener:) failed to return after waiting 10 seconds

The last one appears very rarely. I don't know what am I doing wrong.Can someone help me)?If needed any more information I will provide it!Thanks in advance!

jrturton
  • 118,105
  • 32
  • 252
  • 268
chingi3
  • 91
  • 1
  • 10
  • That's probably not it but nontheless you are return YES on webView:shouldStartLoadRequest: always, even if you're about to pop the view controller ;) I would try to enable NSZombies and put a brakpoint (http://stackoverflow.com/questions/5386160/how-to-enable-nszombie-in-xcode) – krzyspmac May 30 '14 at 14:20

3 Answers3

1

Issue

You are popping your view without leaving ARC to deallocate all objects and delegates, by keeping them alive.

My Solution

For the NSTimer

At @implementation create NSTimer *timer and use it when you want to initialize it. To dealloc it correctly when you pop back, at viewWillDisappear set [timer invalidate] and timer = nil.

For delegates

Set you specific delegates to nil. For example self.delegate = nil

Community
  • 1
  • 1
E-Riddie
  • 14,660
  • 7
  • 52
  • 74
  • but i need timers these timers so I can't invalidate them(!After setting ContentViewController.webView.delegate to nil before popping ContentViewController now there's no crash but sometimes app stucks on ContentViewController without going back. – chingi3 May 31 '14 at 08:33
  • Everytime your view shows up, on viewWillAppear trigger the initialization of the NSTimer and on viewWillDisappear unvalidate it. About delegates, if you are setting it to nil on viewWillDisappear, it means delegate is being allocated and the view is being dismissed. – E-Riddie May 31 '14 at 09:06
  • Timers are in ViewController and webview is in ContentViewController.So which viewWillApear and viewWillDisappear you mean? – chingi3 May 31 '14 at 09:33
  • In ContentViewController set the delegate on viewWillAppear self.webView.delegate = self; and on viewWillDisAppear set it to nil. In ViewController on viewWillAppear initialize the timer and on viewWillDisappear set unvalidate it and set it to nil. – E-Riddie May 31 '14 at 20:31
0

@Yuandra Ismiraldi is right. Your NSTimer will call your updateUI method every 20/10 seconds repeatedly untill it receives [timer invalidate]; instruction. You are getting this error messages as you navigate through your view controller tree. Sometimes your NavigationViewController will need more memory and will release some of un-used objects. In your case some of the previously shown view controllers that still runs the updateUI method every 20/10 seconds. Once this view controller has been released and your selector is called you will receive this crash.

I hope this explains why sometimes you get this crash, and sometimes not.

Pancho
  • 4,099
  • 1
  • 21
  • 32
-1

Your timer code

[NSTimer scheduledTimerWithTimeInterval:10.0 target:self selector:@selector(updateUi:) userInfo:dictionary repeats:YES]

the repeat parameter is set to YES, this make your timer always repeat, thus repeating the sending of the message updateUI after the timer has run for the first time and the view has popped, thus resulting in your error. To make sure your timer only run once, set the repeat to NO

[NSTimer scheduledTimerWithTimeInterval:10.0 target:self selector:@selector(updateUi:) userInfo:dictionary repeats:NO]
  • I am tired of these lazy answers. He doesn't say that he wants his NSTimer to not be repeated, he wants to know why it's happening this and how to fix it. – E-Riddie May 30 '14 at 14:23