Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

Nicsoft

macrumors member
Original poster
Oct 17, 2009
53
0
Stockholm
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
 
How do I do that? Or am I doing something fundementally wrong here.
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.
 
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 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.

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
 
First, make sure you have read through the View Controller Programming Guide for iPhone OS.

1. View1 is displayed and the user touches something on the screen.
Have that touch connected to a View1Controller IBAction method.

2. A new view (View2) appears and the user can make one of four choices.
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:.

3. View2 is closed and information about the choice is sent back to View1.
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:.

4. View1 updates the screen based on the first touch and the choice made in View2. This is now done i drawRect.
Have the viewWillAppear update the choice directly or you can call setNeedsDisplay, which should trigger drawInRect:
 
Here's my thoughts:

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

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.

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

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

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

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.

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

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.
 
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
 
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:

Have that touch connected to a View1Controller IBAction method.

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
 
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
 
For my problem above and the solutions defined by BruinEcon08 and dejo, I cannot solve it without defining my own protocol, can I?
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?
 
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"
 
For my problem above and the solutions defined by BruinEcon08 and dejo, I cannot solve it without defining my own protocol, can I?

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
 
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.

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.

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.

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

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.

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

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.

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

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:

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?

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
 

Attachments

  • ForumApp.zip
    619.1 KB · Views: 80
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!
 
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:

Each custom view controller object you create is responsible for managing exactly one screen’s worth of content. The one-to-one correspondence between a view controller and a screen is a very important consideration in the design of your application. You should not use multiple custom view controllers to manage different portions of the same screen. Similarly, you should not use a single custom view controller object to manage multiple screens worth of content.

Note: If you want to divide a single screen into multiple areas and manage each one separately, use generic controller objects (custom objects descending from NSObject) instead of view controller objects to manage each subsection of the screen. Then use a single view controller object to manage the generic controller objects. The view controller coordinates the overall screen interactions but forwards messages as needed to the generic controller objects it manages.
 
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.
 
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.

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.
 
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.
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.
 
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
 
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 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 (ForumView)?
So, we have three views, correct?
 
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.
 
Yes correct.
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.
 
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!
 
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.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.