how to associate uicontroller to custom uiview programmatically - iphone

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.

Related

how to load custom view with xib on a xib or storyboard

I just want to load a custom view (with xib) on a viewcontoller's xib or stroy board.What is the best practice to do the same.
I have used awakeAfterUsingCoder function code below.
(id) awakeAfterUsingCoder:(NSCoder*)aDecoder
{
BOOL theThingThatGotLoadedWasJustAPlaceholder = ([[self subviews] count] == 0);
if (theThingThatGotLoadedWasJustAPlaceholder)
{
CustomView* theRealThing = (id) [CustomView view];
theRealThing.frame = self.frame;
theRealThing.autoresizingMask = self.autoresizingMask;
return theRealThing;
}
return self;
}
but after using this function my awakeFromNib started calling multiple time.
Please sugegst.
The correct answer currently linked to is overly complicated and buggy, as you have found out. There is a much more standard and better way to do this:
Create an empty XIB
Add a UIView to your XIB so that it is the only top-level object (aside from the proxies First Responder and File's Owner)
Change the class of your new UIView to CustomView
Instantiate the XIB and retrieve your CustomView instance like so:
CustomView *view = [[UINib nibWithNibName:#"CustomView" bundle:nil] instantiateWithOwner:self options:nil][0];
Add it to your view hierarchy in your view controller's viewDidLoad method:
[self.view addSubview:view];
Be sure to override -initWithCoder: in your CustomView subclass in case you need to do any custom initialization. I know this is a lot, so please let me know of any if these steps confuse you or if you get stuck.

How to make UIViewController's view inherit from another UIView?

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

Loading custom UIView from nib, all subviews contained in nib are nil?

I have a custom UIView object with a nib that defines the view/subview layout. My outlets are connected, and when I init the object from initWithFrame: everything is in order.
The problem I'm having is when I'm using IB to embed the UIView into another nib; the custom UIView appears, but none of the subviews it contains appear - in fact their symbols all resolve to nil. I have a very minimal initWithCoder: and awakeFromNib: implementation (just does logging) and my understanding is that as the nib is deserialized the subviews should at least be initialized during the process?
The only conclusion I'm coming to on my own is that one of two things is happening: either my outlet references are corrupt/bad and aren't working, or my understanding of load-from-nib process is faulty and I'm missing something.
Thanks in advance!
Edit: (Code posted for Nekto as requested... as you'll see, it does logging and thats it, heh.)
- (id)initWithCoder:(NSCoder *)aDecoder {
if ((self = [super initWithCoder:aDecoder])) {
NSLog(#"ThumbnailGridView.initWithCoder frame= %f, %f", self.frame.size.width, self.frame.size.height);
}
return self;
}
- (void)awakeFromNib
{
NSLog(#"ThumbnailGridView:awakeFromNib");
}
Edit 2: Nibs, controllers, subviews, etc.
Nibs: I have a single nib containing a UIView. This UIView contains a single UIScrollView, which is filled with a grid of UIViews that are defined in another nib. (Note: this part works fine, as the fill is done programmatically and works with an initWithFrame: call.) The problem here is that the UIScrollView symbol is nil after initWithCoder: and awakeFromNib: are both called, so objects are just being added to nil and nothing happens. If the scrollview symbol was not nil, I'm sure this would work.
Controllers: There are two controllers that utilize this, one is done with initWithFrame: and works perfectly, the other embeds it as a nib-based reference. (As mentioned elsewhere here, defining a UIView in IB, setting the custom class.) I stepped through the code, and that view -is- being initialized properly - only its subviews are "missing".
Does this help give a clearer picture of the situation at all?
You may be misunderstanding how nib loading works. If you define a custom UIView and create a nib file to lay out its subviews you can't just add a UIView to another nib file, change the class name in IB to your custom class and expect the nib loading system to figure it out. You need to modify initWithCoder of your custom UIView class to programmatically load the nib that defines its subview layout. e.g.:
- (id)initWithCoder:(NSCoder *)aDecoder {
if (self = [super initWithCoder:aDecoder]) {
[[NSBundle mainBundle] loadNibNamed:#"CustomView" owner:self options:nil];
[self addSubview:self.toplevelSubView];
}
return self;
}
Your custom view's nib file needs to have the 'File's owner' class set to your custom view class and you need to have an outlet in your custom class called 'toplevelSubView' connected to a view in your custom view nib file that is acting as a container for all the subviews. Add additional outlets to your view class and connect up the subviews to 'File's owner' (your custom UIView).
Alternatively, just create your custom view programmatically and bypass IB.
Check that you are calling the 'super' implementation of initWithCoder: and awakeFromNib in each of your overridden methods i.e.
- (id)initWithCoder:(NSCoder *)decoder {
if ((self = [super initWithCoder:decoder])) {
...your init code...
}
return self;
}
- (void)awakeFromNib {
[super awakeFromNib];
...your init code...
}

How can I assign a view to a controller on iPhone?

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

UIViewController: set self.view to my view or add my view as subview?

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.