Getting access to my controller object from my view class

Discussion in 'iOS Programming' started by Nicsoft, Oct 29, 2009.

  1. macrumors member

    Joined:
    Oct 17, 2009
    Location:
    Stockholm
    #1
    Hello,

    This is what I am trying to do:

    I have created two views, lets call them View1 and View2, in Interface Builder.

    1. From some other view I click a button and then load View1. This is all easily done using a displayView in the controller for for the starting view.

    2. When View1 is loaded, the user can do some things on the screen and then View2 will be loaded. Conceptually (and perhaps practically), at the end of the method (hitTest) that handles the users input, is when I want to change view. I must do it programatically in some way, I assume.

    I have created a my own view class in XCode that is associated with View1 in Interface Builder. It is this class that handles the user's input and should also make sure View2 is loaded.

    The problem is that I don't konw how to access the controller object for View1 (in which I will implement displayView method that displays View2) from my own view class that is associated with View1 in Interface Builder.

    How do I do that? Or am I doing something fundementally wrong here.

    I am very tired, but I hope I made it clear what I want to achieve...

    Thank you in advance!

    Regards,
    Niklas
     
  2. macrumors 603

    jeremy.king

    Joined:
    Jul 23, 2002
    Location:
    Fuquay Varina, NC
    #2
    Introduce your custom view with the view controller via an IB connection (outlet and action)
     
  3. Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #3
    I feel you're doing something fundamentally wrong. Sounds like you're doing things in your view that you should be doing in your viewController. That's it's job. Take advantage of that.
     
  4. thread starter macrumors member

    Joined:
    Oct 17, 2009
    Location:
    Stockholm
    #4
    After doing some trial and error I managed to get it working. Probably made som mistake while loading the nib in the displayView method of my custom view class.

    Some follow-up questions:

    I managed to get it working using my own custom view. But I like the idea that you suggested. Could you please give me the step in order to achieve this. In detail, this is what I want my app do do:

    1. View1 is displayed and the user touches something on the screen.

    2. A new view (View2) appears and the user can make one of four choices.

    3. View2 is closed and information about the choice is sent back to View1.

    4. View1 updates the screen based on the first touch and the choice made in View2. This is now done i drawRect.

    How can I accomplish this without creating my own custom view that I associate with my view in IB but instead using the controll class?

    Thanks again!

    Regards,
    Niklas
     
  5. Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #5
    First, make sure you have read through the View Controller Programming Guide for iPhone OS.

    Have that touch connected to a View1Controller IBAction method.

    That IBAction method instantiates, if necessary, a View2Controller and then calls presentModalViewController:animated: on it or, if you have a navigationController in use, via pushViewController:animated:.

    Again, have some kinda IBAction method, this time in View2Controller that saves the information about the choice (number of ways to achieve this including a property on your appDelegate or a key-value in your NSUserDefaults) and then returns to View1 via a call to dismissModalViewControllerAnimated: or, if you have a navigationController, the user can trigger than via the 'back' button or you can programmatically call popViewControllerAnimated:.

    Have the viewWillAppear update the choice directly or you can call setNeedsDisplay, which should trigger drawInRect:
     
  6. macrumors 6502

    Joined:
    Oct 31, 2007
    Location:
    San José
    #6
    Here's my thoughts:

    You have a CustomViewController that displays a CustomFirstView. The CustomFirstView has a delegate object. When the CustomFirstView is touched, it send a message "closeCustomFirstView:" to its delegate object (CustomViewController). CustomViewController closes CustomFirstView.

    In "closeCustomFirstView:" your CustomViewController displays a CustomSecondView after closing a CustomFirstView. CustomSecondView has a delegate object: CustomViewController.

    When the user closes the CustomSecondView, the view sends a message "customSecondView:closeWithSelection:" to its delegate object. When the CustomViewController receives this message, it closes the CustomSecondView, saves the selection to an instance variable, and opens a CustomFirstView.

    Your CustomFirstView delegate object (CustomViewController) has a method to help drawing "selectionForCustomFirstView:". In your CustomFirstView "drawRect:" method, you call this message to your delegate. The delegate gives the view the right selection.
     
  7. thread starter macrumors member

    Joined:
    Oct 17, 2009
    Location:
    Stockholm
    #7
    Hello,

    Thanks' for your answers. I will look into them. One thing I recon with BruinEcon08 answer, due to me not beeing clear about it, is that I want View2 to be presented above View1 so View1 is still visible under. View2 is not filling up the entire screen and contains different UIButtons for the user to chose between. One problem I noticed while trying this is that View1 is still "touchabel", haven't looked into the problem yet, but I assume it is possible to disable View1 in some way?

    Anyhow, I am in the beginning, I will look into your answers and make a post here about the choices I made when I am done.

    Thank you!

    /Niklas
     
  8. thread starter macrumors member

    Joined:
    Oct 17, 2009
    Location:
    Stockholm
    #8
    Hello, Now I've done some trial and error and things are getting a bit more clear. Time for a follow-up-question relating to both of your answers:

    My View1 is purely a UIView, no other controlls within it. What I need to do is react on the touch on the view, using the coordinates. This works fine when handling the event within the view. But now I want to connect the touch-event with an IBAction of my controller (and delegate) class. Since the view doesn't have any "actions" associated with it that I can map in a similar way (in IB) as, let's say, a UIButton, there's nothing to connect the IBAction to... How to do this?

    One way, I thought, could be to call [super touchesEnded...] in my own custom View1. But reading the document it explicitly tells that one should not call [super touchesEnded...] from a subclass of UIView. Why is that? That could have solved part of my problems. I made a try and it dit call the custom View1's controllers touchesEnded. So functionally, it works...

    Thanks!

    /Niklas
     
  9. thread starter macrumors member

    Joined:
    Oct 17, 2009
    Location:
    Stockholm
    #9
    Hmmm, ok, I make one last try on this thread, and I make it really really simple:

    For my problem above and the solutions defined by BruinEcon08 and dejo, I cannot solve it without defining my own protocol, can I?

    Cheers,
    Nikla
     
  10. Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #10
    No protocol needed. It can be done.

    P.S. Have you considered maybe just putting a big transparent button over the entire View1 (since it has no controls; you're not blocking anything) and hooking up an IBAction to that button?
     
  11. macrumors 603

    jeremy.king

    Joined:
    Jul 23, 2002
    Location:
    Fuquay Varina, NC
    #11
    Assuming you have set the view property on your controller correctly, you can implement the touchesBegan: withEvent: method in your view controller and the event should reach it as it travels up the responder chain...

    Try adding the following to your view controller
    Code:
    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
        
        NSLog(@"RED LIGHT TOUCH!");
    }
    
    Keeping in mind that this is called for any view that the controller "owns"
     
  12. macrumors 6502

    Joined:
    Oct 31, 2007
    Location:
    San José
    #12
    It is actually not too hard:

    Code:
    //  CustomFirstViewDelegate.h
    
    @class CustomFirstView;
    
    @protocol CustomFirstViewDelegate
    
    - (void)willCloseCustomFirstView:(CustomFirstView *)firstView;
    
    @end
    Code:
    //  CustomFirstView.h
    
    @protocol CustomFirstViewDelegate;
    
    @interface CustomFirstView: UIView
    {
        id myCustomFirstViewDelegate;
    }
    
    @property(nonatomic, assign) id <CustomFirstViewDelegate> myCustomFirstViewDelegate;
    
    @end
    Code:
    //  CustomFirstView.m
    
    #import "CustomFirstView.h"
    #import "CustomFirstViewDelegate.h"
    
    @implementation CustomFirstView
    
    @synthesize myFirstViewDelegate;
    
    - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
    {
        [[self myFirstViewDelegate] willCloseCustomFirstView: self];
    }
    
    @end
     
  13. thread starter macrumors member

    Joined:
    Oct 17, 2009
    Location:
    Stockholm
    #13
    Wow, I think I am getting somewhere :)

    The first problem I recon is that I am trying to learn too much at the same time...

    I have managed to create the most of what I wanted, using no protocols designed by myself. I still have some questions, but first I will present how I solved the MOST of my problems:

    The entire project is attached for your reference.

    When clicking the button in the "other" (let's call it the ForumView) view, I use an IBAction method in the controller of that view to load View1.

    When touching the view, the event is caught in touchesEnded in ForumViewController. The information of the x and y of the touched is saved in two variables.

    This view is loaded in the method touchesEnded. I am not using modalview because then I will have a blank screen when removing it and it seems (not sure since there may be other reason) that I don't get a transparent background when using it.

    In View2 I connect the button with an IBAction that handles the removing of the vindow. (removeFromSuperview). I store the data in IBOutlets in order to access from the ForumViewController.

    Code:
    4. View1 updates the screen based on the first touch and the choice made in View2. This is now done i drawRect. 
    
    I didn't manage to trigger drawRect or any other methods from the ForumViewController class. Nowhere is "viewWillAppear" triggered after View2 is removed. In the code you can see that I've tried accessing methods in View1Controller or CustomView1 from ForumViewController, but I get warnings "View1Controller" may not respond to..." But it seems to be working when the method is called when ForumView is loaded.

    Here are my remaining questions:

    1. When launching the application and clicking to present View1 (green background), I can not click to the leftmost (about the first 25px). If you launch the application, check the console, it will print the coordinates (when registering the touch). How come? I have absolutely no idea, in IB it's defined to be positioned to the left and the width is set to 480 (landscape).

    2. When ForumView is presented, how do I make sure that the UIView is not reacting on the touch but only the button? In IB, I did enable "User Interaction Enabled" for the button but disabled it for the view itself. The consequence was that not even the button reacted when touching it.

    3. How come viewWillAppear is not triggered anywhere when removing View2? I tried it in ForumViewController, View2Controller and CustomView. The first time the View1 is loaded it works though, it is loaded in ForumViewController... Where is the "entry point" for my application after View2 is removed?.

    4. Also, why do I get the warning "View1Controller" may not respond to..." when trying to access any method in View1Controller or CustomView from my defined object in ForumAppViewController? It seems to be working the first time ForumView is loaded.

    5. A bit secondary, now...: What is the purpose of using modalViews? I thought it was going to stop the execution of the application until the user had made a selection, but the method where I call for the modalView continues in an asynchronous fashion.

    Dejo:

    I didn't try this, I don't know if it would be any good to me since I already have a working solution for this part. Well, I think at least, the problem I am having now don't seem to be related to this. Thanks anyway!

    I am sorry for all questions, but I have been bouncing my head trying to lear all from Objective-C, C and how XCode and IB relate to each other, and all other relations I need to grasp, a lot to learn...

    Thanks so much for all help so far, it feels like this is the last things before I am over the hill. Hopefully this thread can help others as well. I will post the last code when it's 100% functional.

    Regards,
    Niklas
     

    Attached Files:

  14. Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #14
    I have one lingering question: Have you yet read through the View Controller Programming Guide for iPhone OS?
     
  15. thread starter macrumors member

    Joined:
    Oct 17, 2009
    Location:
    Stockholm
    #15
    Actually I did, two times I think. But my brain has been exposed for too much info lately, having some problem digesting it all... I do understand why you ask though!
     
  16. macrumors 6502

    Joined:
    Oct 31, 2007
    Location:
    San José
    #16
    I am not sure that it is a great idea to be using multiple view controllers. I think that one view controller could do the job for you and also give you a cleaner project.

    Specifically, I will quote this passage from the View Controller Programming Guide:

     
  17. Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #17
    That passage you quoted suggests to me that Nicsoft should not be using a single view controller. He has multiple screens worth of content therefore he should not be using a single custom view controller.
     
  18. macrumors 6502

    Joined:
    Oct 31, 2007
    Location:
    San José
    #18
    This actually made me believe that the OP was trying to achieve a sort of "heads-up display" effect with the second view -- making the second view a subview of the first view, or making the first view and second view both subviews of some parent view.

    The "view" property of the view controller is pointing to the parent view (or the first view) and just brings in the right views when needed. That was my impression, anyway.
     
  19. Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #19
    Ah, sorry. Forgot that part. Yeah, a single view controller is in order then.

    Nicsoft, if I get a chance today, I may check out your project and see if I can understand what you are trying to do.
     
  20. thread starter macrumors member

    Joined:
    Oct 17, 2009
    Location:
    Stockholm
    #20
    Hello, Thanks for helping out. I have had a break from this project for a couple of days, resting my head and other things of priority. Time to continue... Sounds like BruinEcon08's suggestion is the way to go then, am I correct? I was working on a strategy more in Dejo's line...

    Dejo, if you checked out the project, it's actually just a skeleton project for what I am trying to do, it doesn't show the purpose of the application. Shortly it's a game with brics. The absolute first view will present a menu with headings like "Play", "High score", etc. View1 presents brics that is part of the game (quite dynamic how those will be positioned). View2 gives the options in which way to move some brics, four buttons, one for each direction. Does this make the content of View1 "worth of content"? Should View1 have it's own controller that handles the game logic or should it be included in the absolute first view controller (ForumViewController)?

    Thanks!
    Niklas
     
  21. Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #21
    So, we have three views, correct?
     
  22. thread starter macrumors member

    Joined:
    Oct 17, 2009
    Location:
    Stockholm
    #22
    Yes correct.

    I am a bit wiser, I removed the loading of nib-files in ForumViewController and removed the declaration of the view controllers in the ForumAppViewController.m file since I did map the Outlets. I assume it's possible to do everywhere, haven't gotten that far yet though.
     
  23. Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #23
    Alright, now that I'm clear on that, here's how I would set up your views / controllers: have a viewController for your menu view (it'll be responsible for, among other things as needed, bringing up your second, main viewController), and this second viewController will be your main game viewController that handles things for View1 and View2.
     
  24. thread starter macrumors member

    Joined:
    Oct 17, 2009
    Location:
    Stockholm
    #24
    Ok, it makes sense. I'll go for that. Hopefully I have all information now to complete the structure, otherwise it may happen that I'll bump in here again...

    Thanks a lot for all help!
     
  25. thread starter macrumors member

    Joined:
    Oct 17, 2009
    Location:
    Stockholm
    #25
    I still need to have a controller for View2, don't I? If not, I guess it's not possible to load the nib-file or defining any IBOutlet for it, is it?

    I just return the view after I have loaded the View2Controller and don't care about the controller anymore, and use View1Controller as a delegate for View2, correct?

    I thought the answer implied that I should not have ny controller for View2, hence the question.
     

Share This Page