If I have a UIView, called " someView", than, I have a controller, which is called "myController".
I want to assign the someView with myController, how can I do so in code? Thank you.
Basically:
Read what #Lou Franco suggests.
Implement the load view like that:
- (void)loadView {
[super loadView];
MyCustomView *view = [[MyCustomView alloc] initWithFrame:self.view.frame];
self.view = view;
[view release];
// Setup other views if needed
}
From:
http://developer.apple.com/iphone/library/documentation/UIKit/Reference/UIViewController_Class/Reference/Reference.html
If you specify the views manually, you must implement the loadView method and use it to assign a root view object to the view property.
Read about loadView here:
http://developer.apple.com/iphone/library/documentation/UIKit/Reference/UIViewController_Class/Reference/Reference.html#//apple_ref/occ/instm/UIViewController/loadView
Related
I have one UIViewController without NIB file. Now i have one my customized UIView. I want to make UIViewController's view inherit from my customized UIView, is it possible ? I know that if I have XIB file than I can make Custom Class from there but without XIB can it be done?
Thanks in Advance
If you are using a UIViewController subclass, and don't want to use a nib file, then override the loadView method in your subclass:
#implementation MyViewController
- (void)loadView {
self.view = [[MyView alloc] init];
// additional view setup here
}
If you are just using a generic UIViewController (not a subclass), then you might be able to just assign to the view controller's view property, like this:
vc.view = [[MyView alloc] init];
But I'm not sure if that works properly outside of loadView. I haven't seen any documentation that says it is or is not allowed.
Replace your view controller's view like this:
// ViewController.m, in viewDidLoad
self.view = [[MyCustomView alloc] initWithFrame:self.view.bounds];
A more conventional alternative is to fill the default view with the custom subview, like this:
MyCustomView *myCustomView = [[MyCustomView alloc] initWithFrame:self.view.bounds];
[self.view addSubview:myCustomView];
I think you need to load a custom view programmatically, for that you need to override the loadView method of your view controller.
-(void)loadView
{
[super loadView];
CustomView *view = [[CustomView alloc]initWithFrame:self.view.bouds];
[self.view addSubview:view];
}
Replace this in your .h file
#interface ViewController : UIViewController
with
#interface ViewController : Customized View Controller
I have a UIViewController called LaunchController that is launched in my iPhone app when the app first opens:
#interface LaunchController : UIViewController<UINavigationControllerDelegate, UIImagePickerControllerDelegate>
Then, when a button is clicked, I push another view controller:
MainController *c = [[MainController alloc] initWithImage:image];
[self presentModalViewController:c animated:NO];
MainController has the following constructor, which I use:
- (id)initWithImage:(UIImage *)img
{
self = [super init];
if (self) {
image = img;
NSLog(#"inited the image");
}
return self;
}
and then it has a viewDidLoad method as follows:
- (void)viewDidLoad
{
NSLog(#"calling view did load");
[super viewDidLoad];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
[self.view addSubview:imageView];
NSLog(#"displaying main controller");
}
When the program runs, I see that the constructor for MainController is called (due to the output of NSLog), however viewDidLoad never gets called, even though I am calling presentModalViewController. Why is this? Why isn't viewDidLoad being called?
I think it is something as followings. When you need the property of view inside UIViewController, it will be loaded with lazy manner.
- (UIView *)view
{
if (_view == nil) {
[self loadView]; //< or, the view is loaded from xib, or something else.
[self viewDidLoad];
}
return _view;
}
After the view initialized, it will call viewDidLoad to inform the UIViewController.
You aren't loading your view controller from a xib file, and from comments you don't have anything in loadView (which is where you would create your view controller's view if you were not using a xib file).
Therefore, your view isn't being loaded, so viewDidLoad is never called.
Typically you would use initWithNibName: to initialise a new view controller, and then set the image after it (so expose the image as a property).
viewDidLoad will be called as soon as your controller's view property is accessed, that is when you display it for the first time or request it (e.g. have some code that calls c.view.
The reason viewDidLoad is not being called is because you aren't loading a view.
In your init method:
self = [super init];
means that you are just creating a naked view from scratch. not loading one from a nib.
try this instead:
self = [super initWithNibName:nil bundle:nil];
If you have a xib or nib file with the same name as the view controller class it should find if. Otherwise, you can just give a nibName that works.
UPDATE:
If you are not using nib files, then the appropriate method is NOT viewDidLoad. You have to implement loadView instead of viewDidLoad.
In your specific case, just put everything that is currently in viewDidLoad into loadView.
Can anyone explain why viewDidLoad does not get called when loadView is used? It's my understanding that viewDidLoad should still get called.
- (void)loadView
{
CGRect currentFrame = [[UIScreen mainScreen] applicationFrame];
UIView* myView = [[UIView alloc] initWithFrame:CGRectMake(currentFrame.origin.x, currentFrame.origin.y, currentFrame.size.width, currentFrame.size.height)];
myView.backgroundColor = [UIColor redColor];
self.view = myView;
[myView release];
[super loadView];
}
- (void)viewDidLoad {
//this never happens
NSLog(#"VIEW DID LOAD!");
[super viewDidLoad];
}
I've just found out that viewDidLoad won't be called if you call loadView manually in your application.
If you call loadView manually you have to call viewDidLoad manually as well.
More over according to apple docs you shouldn't call [super loadView] as it will overwrite your view with a default UIView.
You must have a warning here:
NSLog("VIEW DID LOAD!");
Instead, you should write like this (the # sign is necessary):
NSLog(#"VIEW DID LOAD!");
viewDidLoad will not get called when you create instance of ViewController. When you are pushing it to navigation controller or present it as model viewcontroller, then only the viewDidLoad get called. Until and unless you are presenting viewController, these delegate will not get called. And one more thing, if your viewcontroller presentation over, and still it remains in the stack or memory, then viewDidLoad method will not get called again because its already load the view. Then viewWillAppear and viewDidAppear delegates only get called when you present the same viewController.
I have a custom UIview which is created programmatically. How to associate to it a custom UIViewController (programmatically as well)
Thanks and regards,
Implement loadView in the UIViewController to create a view hierarchy programmatically without a nib file.
- (void)loadView {
// allocate the subclassed UIView, and set it as the UIViewController's main view
self.view = [[[UIViewSubclass alloc] initWithFrame:CGRectMake(0, 0, 320, 460)] autorelease];
}
You can continue setting up the view/subview hierarchy in two ways. One is to add them in the custom UIView's initialization method, like so:
// in the MyView.m file
- (id)initWithFrame:(CGRect)f {
if (self = [super initWithFrame:f]) {
// add subviews here
}
return self;
}
The second way is to continue using the loadView method implemented in the UIViewController subclass, and just using [self.view addSubview:anotherView]. (Alternatively, use the viewDidLoad method in the UIViewController subclass.)
Note: Replace initWithFrame: with whatever the custom UIView's initialization method is (e.g., initWithDelegate:).
Say the view you created is called newView and the controller is newController. The simple approach would be:
newController.view = newView;
But I'd rather subclass UIViewController and override its - (void)loadView and - (void)viewDidLoad methods and create and/or manipulate the view there - that's the way Apple wants you to do it, and for good reason.
I have a question about UIViewController's subview, I created a UIView subclass MainView, which has the exact size of the screen, I wonder which is a better way of adding MainView, consider the following factors:
1 As MainView has same size as the whole screen, the MainView itself may have subviews, but there is no views at the save level as MainView(ie I don't need to add other subviews to self.view).
2 If I use self.view = mainView, do I put the code in loadView(as the viewDidLoad method means the view(self.view) is already loaded)? I see the loadView method is commented out by default, if I add the code to this method, what other code do I need to put together(e.g. initialize other aspects of the application)?
3 If I add mainView via [self addSubview:mainView], are there actually two off screen buffer? One for self.view, one for mainView, both has same size as the screen and one is layered on top of the other(so it wastes memory)?
Thanks a lot!
I'm not sure I completely understand what you're asking, but I'll try to answer a few of the questions you have.
First of all, if you have multiple UIViews on the screen they are all loaded into memory. You have to do -removeFromSuperview and release them to get the memory back.
You can assign your UIView as the UIViewController's view. For example:
MainView *mainView = [[MainView alloc] initWithFrame:CGRectMake(320.0, 480.0)];
self.view = mainView;
[mainView release]; //since the .view property is a retained property
in that case, you have have the view's initialization code in the -init method. Just redefine it like:
- (id)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
//initializations
}
return self;
}
You must implement loadView if you did initialize your view controller with a NIB.
UIViewController takes care of sizing its "main" view appropriately. This is all you need to do:
- (void)loadView
{
UIView* mainView = [[[UIView alloc] initWithFrame:CGRectZero] autorelease];
self.view = mainView;
}
I'd solve all of this by doing it in a xib! If you create a UIView in your xib, you can then change it's class (when you select the UIView there should be a text field in the Class Identity section of the Identity inspector* - type 'MainView' here!)
Then, create your view controller by calling
myViewController = [[MainViewController alloc] initWithNibName:#"MyNibName" bundle:nil];
That should solve your problems; it's the main subview of your view controller (directly accessable from self.view) and you don't need to worry about memory usage, there's only one view :)
Sam
NB * Click tools -> Identity Inspector. I didn't know it was called this until I had to write this answer!
Yes, the first code-snippet shown above is the "standard" approach, AFAIK, when not using (evil!) NIB files -- i.e. when alloc'ing your view in-code, via loadView.
Note it seems one can also get away with the following, instead of hard-coding the screen-rect size:
UIView *myView = [[UIView alloc] initWithFrame:[UIScreen mainScreen].applicationFrame];
self.view = myView;
[myView release];
Note you definitely want to do the [myView release] call since, indeed, as pointed out above, self.view (for UIView) is a retained property.
Cheers, -dk
Perhaps the most important thing to do is make sure you have the following:
self.view.userInteractionEnabled = YES;
While it might not be required all of the time, it fixes the issue where self.view is unresponsive. This issue pops up occasionally.