I often see this line of code
[super awakeFromNib]
in the awakeFromNib method in the implementation of a view controller
My understanding is it is telling the super class of this view controller (which would be the window) to awakeFromNib.
Am I right? If so, why do we have to tell the window to awake in the awakeFromNib method of a UIView Controller sub-class?
My understanding is it is telling the super class of this view controller ...
right so far...
(which would be the window)
oops - that's the source of your confusion.
The "super class of the view controller" is UIViewController. "super" is referring to the base class that your UIViewController sub-class inherits from; it doesn't have anything to do with the window that encloses your view.
So, what this is doing is invoking the default awakeFromNib implementation of a basic UIViewController, in addition to whatever you're doing in your sub-class implementation.
What David said above is correct,
Now for your question "why do we have to tell the window to awake in the awakeFromNib method of a UIView Controller sub-class?"
if there is any custom modification or any data that you want to load before your ViewController loads we should use the awakeFromNib.
awakeFromNib is called when the controller itself is unarchived from a nib.
Related
I want to make my code more modular and flexible.
So rather than setting a the tableViewDelegate as the UIViewController, I have a subclass of UITableViewController as the tableView data source and delegate.
Basically, the original UIViewController provides the view for the subclass of UITableViewController.
That way similar tables can be used by several UIViewController's subclasses.
In some cases, UIViewController's provide the tableView and I just switch the tableView delegate at run time.
Works well.
Here is the code for BGTableViewDelegateMother that inherits from UITableViewController (that inherits from UIViewController.
#implementation BGTableViewDelegateMother
-(void) setDelegate:(id<BGTableViewDelegateMother>)delegate
{
_delegate=delegate;
self.view = self.delegate.tvDelegated; //So that viewWillAppear would work fine
[self view]; //load the view view didload is not called either
self.delegate.tvDelegated.delegate =self;
self.delegate.tvDelegated.dataSource=self;
}
Okay. The UITableViewController.view is used for one thing. Now that it points to the correct tableView, I expect viewWillAppear to be called. It's not
I think everytime the tableView will be shown, I should at least reloadData
-(void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];//never called
[self.delegate.tvDelegated reloadData];
}
This code never called. Even though the view will indeed appear. Why?
viewDidLoad is also never called.
Make the table view controller a child view controller of your view controller while its view is linked (and it is the data source) and could be on screen. This tells the view controller hierarchy that the table view needs to know about the appearance callbacks.
Let's say I have a view controller called vc1, which a synthesized property called property1, and i wants to access it from another view controller (vc2) and change it from vc2.
Now the methods created by the #syntisize to change and get properties are instance methods, so how can I get to them fro another view controller (do view controllers have instances in the app, and if so, what are they?)
Just to be clear I am using storyboards, so I never really instantiate the view controllers...
VC1.m:
-(void) yourMethod {
...
}
VC2.m
YOURViewController * vc2 = [[YOURViewController alloc]init];
[vc yourMethod];
[vc release];
Make sure to import your YOURViewController in your other view .m file
Something like that should work.
Or if you're having problems, try this tutorial here:
Tutorial on How-To Pass Data Between Two View Controllers
Hope this helps :)
While you can do it the way you describe, I think the common technique (assuming VC1 has a segue to VC2) is a bit different, where VC2 will have a property that will be set by prepareForSegue. See Configuring the Destination Controller When a Segue is Triggered in the View Controller Programming Guide.
You will need to link the storyboard views with the viewcontrollers so the view for vc1 would use the class vc1 etc for the rest (I assume you have done this because this is important when coding for different views)
Then all you need to do is where ever you are calling the properties so lets say the viewDidLoad method, declare the view controller like this:
- (void) viewDidLoad {
vc1 *viewController;
// Now you change the variable I'll presume its a UILabel so I'll change its text [viewController.property1 setText:#"I changed a different views UILabel"];
}
Let me know whether this works... Its worked for me before so should work
I have a view called GameViewController. I didn't set it up but it seems to be a UIKit view with an embedded EAGL view.
I set up gesture recognizers for tap and swipe on my GameViewController. They work great, except the method I set up as a selector for tap (a function within GameViewController) gets called on touchesEnded, not touchesBegan.
Only way to get at the touchesBegan function is to subclass.
So, I subclassed UITapGestureRecognizer, created a touchesBegan function, and NSLogs in there get called on touch down. However, I can't call any functions in GameViewController from the UITapGestureRecognizer subclass. (Class method +METHODIWANTTOCALL not found).
I realize I need "references" back and forth but what should they be? Or is this totally the wrong approach? Do I delegate? (I'm new to that) What is the best way to have a method within GameViewController called from this UITapGesture subclass?
It seems like your GameViewController is a singleton class (only one instance of this class in the app). You can have a class method in GameViewController that returns the instance of the singleton. Then you can just the method regularly:
In Recognizer:
GameViewController* myController = [GameViewController getInstance];
[myController handleTouchBegin];
Alternatively, you can define your handleTouchBegin as a class method if it does not need to know any internal state:
[GameViewController handleTouchBegin];
I have setup tab bar controller using interface builder, and each tab bar item is linked to a view controller (4 tabs, 4 view controllers). I want to know if Interface Builder uses an -init method to initialize the view controller because apparently this method does not get called:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil;
... and I want to do some initializations. I can't add that to -viewDidLoad since it is recalled in case of memory warning. Any idea?
Objects loaded from a *.(nib|xib) are inited with:
- (id)initWithCoder:(NSCoder *)inCoder;
So you could override that or if doing your setup after -initWithCoder: is called is not a problem you could use:
- (void)awakeFromNib;
from the NSNibAwaking protocol.
I was also going to mention initWithCoder vs awakeFromNib.
In general, I override initWithCoder when allocating memory for the object or setting values. When you need to do some setup after the IBOutlets are connected, then override awakeFromNib. Until then, IBOutlet instance variables to other views and controls are not connected.
Sounds like you want to implement -(void) awakeFromNib.
NSNibAwaking Protocol Reference (requires ADC login)
This should be straight forward for a guru. I don't have any code really written out, just a couple of controllers and a custom UIView. All connected through nibs. The app loads without crashing, yet I can't see my NSLog() hit from my custom UIView.
My application delegate has default template code which calls for a class of mine called TabAnimationController. TabAnimationViewController has its view set to TabView. I made sure that in TabAnimationViewController's NIB that File's owner is set to TabAnimationViewController and that my instance of UIView has its class set to TabView.
In TabView.m I'm trying to see how NSLog is going to hit, and it's not showing up at all.
- (void)loadView {
NSLog(#"calling loadView");
}
- (id)initWithFrame:(CGRect)frame {
NSLog(#"Calling initWithFrame:");
return self;
}
Strange. I'm not sure why even after proper IB connections that my NSLog will not show up. Only anything put into drawRect: will invoke. Why isn't initWithFrame or loadView ever get hit? What if I want to customize this view programmatically?
First of all, when a view is dehydrated from nib file, instead of initWithFrame, initWithCoder is invoked. So you need to implement your initialization in initWithCoder as well. (It may be a good idea to keep the initWithFrame initialization as well, if you anticipate programmatically creating your TabView instead of hooking up in the IB. Just refactor your initialization to another method and call it from both implementations.)
Also in your initialization code above you must always call the super class's initialization. There is a boiler plate pattern all custom classes use in their init implementation for that:
if (self = [super initXXX]) { do your initialization }
return self;
Second, loadView which is actually a UIViewController method and not a UIView method is invoked only if the view outlet of the controller is nil.
Unless you are composing your view yourself programmatically using your controller, you do not need to override loadView. Instead you should override viewDidLoad, which is called after the view is loaded, to do additional initialization.
The simplest way to get this up and running is simply to use the "View based Application" template when you create a new project. It sets up everything you need to start with.
But, in short, you're looking at the wrong methods. First, you shouldn't override loadView unless you're creating your view programatically. If it's loading from a XIB file look at the initWithNibName method.
You might also want to look at the viewDidLoad, viewWillAppear and viewDidAppear methods that are triggered, well, it's fairly obvious when!