I'm not instantiating my controls/views manually. I've set up a storyboard like this:
-> UITabBarController-> UINavigationController-> HomeViewController
I switched the controller class of the last to my own HomeViewController.
Here's the code:
#interface HomeViewController : UIViewController {
UIView *buttonView;
UITableView *buttonTableView;
}
#property (nonatomic, retain) IBOutlet UIView *buttonView;
#implementation HomeViewController
#synthesize buttonView;
Inside the main view for HomeViewController there's a subview (UIView) that is hooked up to the outlet by ctrl-dragging one of those lines.
But I can't for my life find a method on UIViewController to override that will be invoked somewhere in the life cycle. So far I've tried putting my stuff in
// didn't expect it to work
-(id)init
// didn't expect it to work
-(id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
// had hopes for this one, but no such luck
-(id)initWithCoder:(NSCoder *)aDecoder {
// this one looked promising...
-(id)awakeAfterUsingCoder:(NSCoder *)aDecoder {
// not much hope
-(void)awakeFromNib {
// my main candidate for a long while...
-(void)viewDidLoad {
When I run the interface loads perfectly, I get my tabs, my navigation bar, my view. But no matter how much NSLog() I do in HomeViewController there's never any output in the console.
Am I missing something about the lifecycle of the storyboard? Is my controller not instantiated or used?
viewDidLoad is called with a storyboard, something is wrong with your storyboard setup. Sounds like it is loading a standard UIViewController rather than your HomeViewController subclass. Make sure the HomeViewController class setup in the storyboard.
The problem was that I recently renamed the storyboard and didn't realise Xcode does not rename the Main Storyboard setting. I've cleaned the project numerous times and still it seems the old storyboard is present and loaded.
Related
I have these two classes in my project:
#import <UIKit/UIKit.h>
#import "TableViewController.h"
#interface MainViewController : UIViewController
#end
and
#import <UIKit/UIKit.h>
#interface TableViewController : UITableViewController
#end
Within MainViewController.m, I am trying to do this:
TableViewController *tview = [[TableViewController alloc] initWithNibName:#"TableViewController"
bundle:nil];
tview.tableView.dataSource = tview;
tview.tableView.delegate = tview;
[self.view addSubview: tview.view];
However, this is crashing with an:
-[MainViewController tableView:numberOfRowsInSection:]: unrecognized selector sent to instance 0xb52dc90'
I don't understand why MainViewController is becoming the datasource/delegate for the TableViewController, when I already set the delegate/datasource in the init above. I also tried to set TableViewController's delegate/datasource to self from within its viewDidLoad, but the MainViewController still keeps acting as the delegate/datasource, regardless. I tried with the nib files hooked up and not hooked up, but no difference.
Ideally, I want the TableViewController to act as the delegate and datasource, and have its view added to MainViewController. How can I get this done?
Thank you!
Note: Neither solution worked for some reason. In the end, I recreated TableViewController as inheriting from UIViewController and set it as and things went normally then.
Where have you written the TableView delegate methods?? They should be inside your TableViewController Class and not inside the MainViewController Class.
Write the UITableView delegate methods inside the TableViewController Class.
Hope this will solve your problem...
Have you set delegate and datasource to nil in dealloc method?
tview.tableView.delegate = nil;
tview.tableView.dataSource = nil;
I have found quite a lot on this subject but I just can't figure it out. Any help would be massively appreciated!
I have an app set up with a UITabBarController. Within one of the tabs, I am showing a UITableView which is using a UINavigationController to allow for hierarchy. All the tables rotate just fine when the orientation is changed, until I get to what is effectively the final view in the hierarchy.
The final view is not a UITableView, just a basic UIView. But I can not get this page to rotate successfully! I have remade the view from with the absolute basics required and it still doesn't want to work! The code is below but it is currently pretty much a standard template with nothing in it now.
Also, I am not using InterfaceBuilder, and shouldAutorotateToInterfaceOrientation is on all views. This is the only one I am having problems with.
SomeView.h
#import <UIKit/UIKit.h>
#interface SomeView : UIViewController
{
NSString *someID;
NSString *someName;
}
#property(nonatomic,retain) NSString *someID;
#property(nonatomic,retain) NSString *someName;
#end
SomeView.m
#import "SomeView.h"
#import "AppDelegate.h"
#implementation SomeView
#synthesize someID, someName;
-(void)loadView
{
}
-(void)viewDidLoad
{
[super viewDidLoad];
}
-(void)viewDidUnload
{
[super viewDidUnload];
}
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
return YES;
}
-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration
{
NSLog(#"willAnimateRotationToInterfaceOrientation");
}
-(void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
-(void)dealloc
{
[super dealloc];
}
#end
UPDATE 10th Nov 2011
I'm still having this issue, however looking through documents and bits this seems to be my problem (http://developer.apple.com/library/ios/#qa/qa1688/_index.html)
The view controller's UIView property is embedded inside UIWindow but alongside an additional view controller.
You may find a situation where shouldAutorotateToInterfaceOrientation is called once at startup for a given view controller but is never called again when the device is rotated. Because view controllers are tightly bound to the views they manage, they are also part of the responder chain used to handle events. View controllers are themselves descendants of the UIResponder class and are inserted into the responder chain between the managed view and its superview. So it is common practice to have one primary view controller in your application as part of the responder chain. You would typically add one primary view controller such as a UINavigationController, UITabBarController or a generic UIViewController to your UIWindow. For example, this is done by calling:
[myWindow addSubview:primaryViewController.view];
If you add an additional view controller's UIView property to UIWindow (at the same level as your primary view controller) via the following:
[myWindow addSubview:anotherController.view];
this additional view controller will not receive rotation events and will never rotate. Only the first view controller added to UIWindow will rotate.
My UITabBarController stopped to autorotate, when I added a new navigationController to it with a tableViewController and didn't notice, that my custom navigation controller's shouldAutorotateToInterfaceOrientation returns YES only for one orientation. The solution is to check shouldAutorotateToInterfaceOrientation function in each Controller inside TabBarController.
May be it will help to somebody.
And I have figured it out...
I was looking at the code which pushes the UIViewController onto the stack and I had not fully initied the UIViewController.
I have an UIViewController with a UIToolBar at the top with 3 buttons and a UIView, when touch upInside those buttons I have to change the views that the controller has. What can I do to get my porpuse? Thanks in advance.
You probably want to use something like a UINavigationController to control the view stack and then have your button(s) call one of these methods for the Touch Up Inside action:
pushViewController:animated:
popViewControllerAnimated:
popToRootViewControllerAnimated:
popToViewController:animated:
Here is a good uinavigationcontroller-tutorial to look into.
You need to do something like this for each of the actions you set up.
In the .h file of the current viewController:
#import "OtherViewController.h"
#interface MyViewController : UIViewController
{
OtherViewController *otherViewController;
}
#property(nonatomic, retain)IBOutlet OtherViewController *otherViewController;
Then in the .m file of the current viewController you need to add the following for each IBAction (touch up inside).
At the top of the .m file add:
#synthesize otherViewController;
Then make an IBAction and put the following line of code to display the other view:
[self presentModalViewController:otherViewController animated:NO];
In your otherViewController you can dismiss itself by using:
[self dismissModalViewControllerAnimated:NO];
NOTE: The other thing you will need to do is create a UIViewController in Interface Builder for each of the views you plan to display. You need to then go into the identity inspector and set the Class as OtherViewController. You then need to link the IBOutlet to the OtherViewController as normal.
There is a YouTube video tutorial which covers all of what I have mentioned above. It's a nice simple way to get started.
UiViewController view property is the base view you are seeing. It could be set(replaced with another). SO replace the view object of ViewController with another view you created.
UIView * customView = [[[UIView alloc] initWIthFrame:viewFrame] autorelease];
[self setView:customView];
Here self represent the current viewController.
I have created a UITabBarController in my app delegate.
where each tab bar item holds a different UINavigationController that loads a custom UIViewController with a NIB (using -pushViewController:).
Inside one of the navigation controller, I load a custom UIView class with a custom NIB also.
This view is loaded multiple times inside the UIViewController.
The custom UIView has a UIButton, that on the event of touching it, I want to push a new UIViewController on the stack.
Problem is that I 'lost' the UINavigationController that holds the UIViewController.
I know I should use delegates, but haven't figured out who should which class should be the delegate.
Thanks in advance!
Neither .navigationController or .tabBarController will be available for a UIView or UIViewController that's been created but not pushed onto a stack
Either create a property on your View (or ViewController) class that is a UIViewController that is provided optionally after initialization or you could add a third argument to initWithNibName:bundle:
#interface CustomViewController : UIViewController
{
UIViewController *owner;
}
#property (nonatomic, assign) UIViewController* owner;
#end
Then in the owner ViewController:
CustomViewController *cvc = [[CustomViewController alloc] initWithNibNamed:nil bundle:nil];
cvc.owner = self;
It's too bad .parentViewController is read-only, this would be the sensible place for this.
You can get this using UIApplication class. Using this class you can find which viewController is placed at first. Here is the solution link for your problem.
I have the relatively common setup of a TabBarController whose tabs contain NavigationControllers which have TableViewControllers as their roots. I'm trying to perform some logic on initialization of one of these TableViewControllers but can't seem to find what init function gets called.
My goal is to add a listener in the TableViewController (that I have subclassed) which can respond to events by updating the navigationController.tabBarItem.badgeVluew property.
I've tried putting code into initWithStyle: as well as init but neither of them end up getting called. I've also tried putting it in viewDidLoad, but that only gets called once the controller actually appears (I need to have it happen as soon as the controller is loaded / as soon as the tab bar item shows up).
Does anyone know where I would put this code for it to happen on initialization of the controller?
Also, this is all set up through interface builder / NIBs. I'm not adding the nav controller or tableviewcontroller manually, which is why it's not clear what init function I need to override.
If you select one of your UITabBarItems in IB, you will see 'View loaded from "YourView"'. Click into this "gray" View. In the Inspector window you will see in the Attributes Tab (the tab on the left) the title and the NIB name which will be loaded (lets call it "YourNibName").
Now select the right tab of the inspector (Identity) and change the Classname (Combo next to Class) to your "YourViewController" class, which you must create in xcode. Don't use the standard ViewController, which is already selected. The InterfaceBuilder loads your nib and attaches it to your ViewController.
Open YourNibName and change FilesOwner's Class (Inspector, right Tab) to "YourViewController", too.
Your TabBar's NIB contains a FilesOwner, too. Create a ViewController for this FilesOwner and set its Class to this Controller (i.e. TabBarController)
In "TabBarController" you can find out which Tab was selected by using this code:
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController{
if ([viewController.nibName isEqualToString:#"NIBName1"]){
// Do something here, if you like. (i.e. Save the state in a string or int)
}
if ([viewController.nibName isEqualToString:#"NIBNAme2"]){
// Do something here, if you like. (i.e. Save the state in a string or int)
}
...
}
Here you can do something "global" or preinitialize something. This is ONE thing you can do.
INIT OF YOUR VIEWS:
If you select a Tab and the view (which is handled by YourViewController) will be shown for the first time, "viewDidLoad" will be called in "YourViewController"
- (void)viewDidLoad {
// Here you can add views programatically
[self.view addSubview:myNavigationController.view];
[self.view bringSubviewToFront:myNavigationController.view];
// And if you like, do some INIT here
[super viewDidLoad];
}
I hope this is what your question was about.
Now something about the badge. It's a hack, but works fine for me.
Header file:
Add an outlet to your controller, which is representing your TabBarController:
#interface yourController : UIViewController <UITabBarControllerDelegate> {
UITabBarController *tabBarController;
}
#property (nonatomic, retain) IBOutlet UITabBarController *tabBarController;
#end
Connect this outlet in IB with your TabBar.
Implementation:
In your TabBarControllerClass you can overwrite 'initWithNibName':
#synthesize tabBarController;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
// Do some init here
// select your desired item (it will be loaded)
// then you can assign the badge
tabBarController.selectedIndex = 1;
tabBarController.selectedViewController.tabBarItem.badgeValue = #"222";
// and select the item you will start with
tabBarController.selectedIndex = 0;
// if you like you can add a notification, which you can activate from anywhere else
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(itemBadgeChanged:)
name:#"itemBadgeChangedNotification"
object:nil];
}
return self;
}
if you don't use nib, use '- (void)loadView { ... }' instead.
You are using a subclass of the TabBar controller, maybe you can use 'self.selectedIndex = 1;' instead of 'tabBarController.selectedIndex = 1;', and so on. Just try this out
Hope this helps!