presentModalViewController does not want to work when called from a protocol method

Discussion in 'iOS Programming' started by John Baughman, May 21, 2010.

  1. John Baughman macrumors member

    Joined:
    Oct 27, 2003
    #1
    I have a subview that when double tapped a protocol method on the subview's parent view controller is called like this...

    Code:
    - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
        UITouch *theTouch = [touches anyObject];
        if (theTouch.tapCount == 1) {
     
        } else if (theTouch.tapCount == 2) {
              if ([self.delegate respondsToSelector:@selector(editEvent:)]) {
                   [self.delegate editEvent:dictionary];
              }
        }
    }
    
    
    Here is the protocol method with the dictionary consuming code removed.

    Code:
    - (void)editEvent:(NSDictionary){
        EventEditViewController *eventEditViewController = [[EventEditViewController alloc] initWithNibName:@"EventEditViewController"	bundle:nil];
        eventEditViewController.delegate = self;	
    	
        navigationController = [[UINavigationController alloc] initWithRootViewController:eventEditViewController];
        [self presentModalViewController:navigationController animated:YES];		
        [eventEditViewController release];
    }
    
    The protocol method is called and runs without any errors but the modal view does not present itself.

    I temporarily copied the protocol method's code to an IBAction method for one of the parent's view button's to isolate it from the subview. When I tap this button the modal view works fine.

    Can anyone tell me what I am doing wrong? Why does it work when executed from a button on the parent view, and not from a protocol method called from a subview.

    Thanks,

    John
     
  2. PhoneyDeveloper macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #2
    Not sure why it doesn't work but I've occasionally run into similar problems. The normal workaround is to use performSelector:withObject:afterDelay: to perform the task. You might want to do the delayed perform in the view and then call the delegate from the delayed method.
     
  3. TiberiusXavier macrumors member

    Joined:
    Apr 18, 2010
    Location:
    Chicago
    #3
    Just out of curiosity, what happens if you present eventEditViewController instead?
     
  4. John Baughman thread starter macrumors member

    Joined:
    Oct 27, 2003
    #4
    I probably should have posted the things that I have tried all without success.

    1. Restarted xCode and the simulator
    2. Ran on the device (iTouch)
    3. Presenting eventEditViewController instead of navigationController
    4. Using Push instead of presentModal.
    5. delaying the call to the protocol with performSelector directly to the protocol, to another method in the subview which calls the protocol method, from the protocol method to another method with the presentModal calls.
    6. Using a timer.

    I have it currently setup so that the protocol method calls a known working method that presents a different view. Before calling presentModalViewController it pops a UIAlertView which works every time, but if but the modal view refuses to display when called via the protocol method.

    I'm stumped. Perhaps it has something to do with the fact that I am calling the protocol method from a UIView class instead of a UIViewController class. Maybe I need to create a UIViewController for the subView??

    Thanks for any help.

    John
     
  5. PhoneyDeveloper macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #5
    TX's point is well taken. Why do you create a navigation controller in that code? Why don't you present the new view controller that you just created?

    I assume that editEvent is a method on the view controller. In that case a simple

    Code:
    - (void)editEvent:(NSDictionary){
         EventEditViewController *eventEditViewController = [[EventEditViewController alloc] initWithNibName:@"EventEditViewController"	bundle:nil];
         eventEditViewController.delegate = self;	
         [self presentModalViewController: eventEditViewController.delegate animated:YES];		
         [eventEditViewController release];
    }
    
    should work. Why don't you do this?

    You need to explain this more fully. The usual structure is that you have a view controller and it manages views. The view controller serves as delegate to the various views that need delegates. The view controller should be able to presentModalViewController in response to a delegate message from any views. Is your structure different than this?
     
  6. John Baughman thread starter macrumors member

    Joined:
    Oct 27, 2003
    #6
    I have tried presenting eventEditViewController directly without the navigation controller and it didn't work either. A quick question, in your sample code you used eventEditViewController.delegate. Is the .delegate a type? Don't think that is right. I get a build error if I use the delegate property.

    I am still getting my mind around xCode, and I think I still do not quite understand the proper way to create views programmatically. In this case I have a nib with a view inside of a scroll view. The view ID is the UIView Class BodyClock and is wired to the viewController's IBOutlet bodyClock. The BodyClock's drawRect method creates a complex graphic using CGContextRef and CGPathRef functions. On top of the graphic I need to programmatically display small event banner views that will respond to touches so I created a UIView class called EventBanner. It all looks like this...

    AppNameAppDelegate.h
    AppNameAppDelegate.m

    AppNameViewController.h responds to the protocol method edtiEvent:
    AppNameViewController.m
    AppNameViewcontroller.xib

    BodyClock.h (UIView)
    BodyCock.m

    EventBanner.h (UIView - declares a protocol with the method editEvent:)
    EventBanner.m

    As indicated above the EventBanner class defines the protocol method editEvent: and AppNameViewController responds to that protocol method.

    So from the ViewController I setNeedsDisplay on bodyClock. BodyClock's DrawRect draws the graphic then for each event on file it instantiates an EventBanner view and adds it as a subView to itself.

    When the user taps an EventBanner view an alert opens which includes an Edit button. When the user taps the Edit button I call the protocol method on the view controller.

    So...

    ViewController [bodyClock setNeedsDisplay] -> BodyClock drawRect creates and adds EventBanner views to itself as subviews.

    User taps EventBanner view -> UIAlert ->User taps Edit -> EventBanner calls editEvent: on ViewController -> View Controller presents EditEvent view.

    Is this the correct way to do this? Am I even close?

    Thanks

    John
     
  7. PhoneyDeveloper macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #7
    OK, that's a little complicated. It mostly sounds OK except that it's not common to add a subview inside drawRect. I'm not sure if that's a problem but I wouldn't do it that way. I'd add the subviews in response to the touches.

    I'm not clear on exactly when the editEvent protocol method is called. You say there's an alert and the method is called when a button in the alert is tapped. Does that mean that the protocol method is called when the alert goes away?
     
  8. John Baughman thread starter macrumors member

    Joined:
    Oct 27, 2003
    #8
    The eventBanner subviews are displayed before the user has any interaction with them.

    However, :) , your comment regarding it not being common to add a subview inside drawRect got me on the right track. I moved the creation of the BannerEvent subviews to the view controller. At first I tried adding the subviews to the bodyClock UIView and that did not work. The views did not show up. I then added them to the UIScrollView that bodyClock was in and voila they showed up and the protocol method in the view controller works, presentModalViewController and all!!

    Thank you so much.

    John
     

Share This Page