UITabBarController as a delegate of its sub view controllers - iphone

I currently have a Storyboard with a subclass of UITabBarController linked to 3 view controllers.
Those view controllers are custom subclasses of UIViewController, and I added a "delegate" property, as I need to access a property (settings) from the main view controller (retrieved from a .plist file).
It's a Settings class that handle reading and writing from/to this file.
Anyway, I haven't found how to set their delegate property from IB, so I added this in the code :
- (void)viewDidLoad
{
[super viewDidLoad];
/* Fetch settings */
NSString* settingsPath = [[NSBundle mainBundle] pathForResource:#"Settings" ofType:#"plist"]; // Load settings from file
settings = [[Settings alloc] initWithContentOfFile:settingsPath];
for (UIViewController<HasDelegate> *c in [self viewControllers]) {
c.delegate = self;
}
}
But only the 1st view controller (the one that is displayed when starting the app) can access it.
The other ones has a nil pointer for the delegate property.
Is it the right way to do it ?
What am I missing ?

Nevermind, I was accessing the UINavigationController, instead of its rootViewController. I added :
if([c isKindOfClass:[UINavigationController class]]) {
NSLog(#"UINavigationController");
UINavigationController *navC = (UINavigationController*)c;
[[[navC viewControllers] objectAtIndex:0] setDelegate:self];
}
and it works like a charm !

Related

iOS strange delegate behavior?

I have a really strange delegate behavior in iOS. I'm setting a custom delegate in a subclassed UIViewController like this:
- (void)viewDidLoad
{
[super viewDidLoad];
self.baseNavigationBar = [[BaseNavigationBar alloc] initWithNibName:nil bundle:nil];
self.baseNavigationBar.delegate = self;
self.baseNavigationBar.navigationController = self.navigationController;
[self.navigationController.navigationBar addSubview:self.baseNavigationBar];
}
The initWithNibName can use nil, when using the default nib, because internally it will check fora nil in the nibName.
if (!nibNameOrNil) {
nibNameOrNil = NSStringFromClass([self class]);
}
The delegate declaration from the baseNavigationBar object looks the following:
#property (nonatomic, retain) id<BaseNavigationBarDelegate> delegate;
/*same thing with assign, which I you should use*/
/*and in the .m of course #synthesize*/
And now 2 screenshots from the running application.
The first one show's the debugger values from the BaseListViewController, which is a subclass of BaseCoreViewController, which is a subclass of UIViewController.
The screenshot is taken, when the viewDidLoad method is called.
The second one show's the values from the BaseNavigationBar, which is a UIView subclass.
The screenshot is taken at a time, when the user clicks the "next" button
- (IBAction)nextAction:(id)sender {
if (self.delegate) {
[self.delegate navigationBarDidClickNextButton:self];
}
}
So why is this a problem? By clicking a button in the BaseNavigationBar my delegate is always nil, so the program is stuck. But when looking at the values from the BaseCoreViewController at the same time the delegate is not nil. Very strange.
Edit
The BaseNavigationBar is loaded from a nib file using the UINib loadNibNamed:owner:options: function.
Edit 2
So that's pretty much all of the code.
Edit 3
Finally we got the source of the error in the last pieces of the code... setting self = something totally not allowed...
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if (!nibNameOrNil) {
nibNameOrNil = NSStringFromClass([self class]);
}
if (!nibBundleOrNil) {
nibBundleOrNil = [NSBundle mainBundle];
}
NSArray *topLevelObjects = [nibBundleOrNil loadNibNamed:nibNameOrNil owner:self options:nil];
/*Here is the bad part*/
self = [topLevelObjects objectAtIndex:0];
state = BaseNavigationBarButtonStateNext;
if (self) {
self.title = #"";
}
return self;
}
Solved using a Class method instead of defining a custom init.
If you are using nib file, you should declare the nib class while initialising your class object.
You have initialised initWithNibName:nil
self.baseNavigationBar = [[BaseNavigationBar alloc] initWithNibName:nil bundle:nil];
but it should be like initWithNibName:#"BaseNavigationBar"
self.baseNavigationBar = [[BaseNavigationBar alloc] initWithNibName:#"BaseNavigationBar" bundle:nil];
Not sure what the problem is. Require some more code to analyze the problem. But what I can see is address of BaseNavigationBar in both the screen shots is different. It means the BaseNavigationBar object present in the controller is not the one which got the nextAction event as in second screen shot.

Draw SubView in Storyboard

I want to present a modalView (it can be a viewController) that I draw in Storyboard. I don't want to have to make the whole thing programmatically. Is there a way to do this without it being a full screen view?
I guess another way to ask the question is: how do I [self.view addSubView:mySubView] where mySubView is drawn in InterFaceBuilder/Storyboard?
To do this properly, you should look at View Controller containment in the docs. Basically you would addChildViewController after instantiating the viewController from your storyboard and then add the viewController's view to your current view hierarchy.
To just get it working however, the following will get you going:
UIViewController *childViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"<identifier you set in Interface Builder>"];
[self.view addSubView:childViewController.view];
Note that one of the reasons to do it 'properly' will be to ensure that autorotation and presentation callbacks are sent to the sub view controller.
Override the initWithCoder method in the object-c class.
- (id)initWithCoder:(NSCoder *)aDecoder {
if ((self = [super initWithCoder:aDecoder])) {
[self addSubview:[[[NSBundle mainBundle] loadNibNamed:#"MyView" owner:self options:nil] objectAtIndex:0]];
}
return self;
}

Push a view from a nib file using a right navigation bar button

As described in the title, i would like to push a view, from a known NIB, using a button on the navigation bar. I'm working on a UINavigationController app.
I already added the right button in IB and i linked it to the method that is in the RootViewController
I have searched everywhere but I couldn't find a way to do this method...
-(IBAction)addItems:(id)sender
{
?
}
I also tried this solution, but it isn't working either...
For example:
-(IBAction)addItems:(id)sender
{
CustomController *controller = [[CustomController alloc] initWithNibName:#"CustomController" bundle:nil];
[self.navigationController pushViewController:controller animated:YES];
[controller release];
}
Where
CustomController name of your custom controller class.
#"CustomController" name of your xib file
If you just need the view from nib file, then try this..
NSArray* nibViews = [[NSBundle mainBundle] loadNibNamed:#"QPickOneView"
owner:self
options:nil];
UIView* myView = [ nibViews objectAtIndex: 0];
self.view = myView;
If you want to push a ViewController..Then go with the Nekto's Answer.

place xib in UIView control iphone

I know how to place a nib file in the "main" view controller:
when I execute this method a new nib file will be displayed.
Is it possible to place that nib file in a UIView controller instead?
I want to place that nib file in that view controller instead of in the main view. How could I do that?
Edit:
I tried doing what you mention Paul I don't know what am I doing wrong. Anyways here is what I did:
I created another view controller with the properties an methods you mentioned.
I hooked up my IBoutlet UIView *exampleView to the base view:
then from here I am lost I don't know where to place the other methods. I would like to place that exampleView into:
that view.
I have tried placing them in pgBackground.m but it does not work. I want to place them inside an IBaction so that I can load that with a touch up inside event with a button.
I managed to place a nib file in a uiview control but I have the problem that the subview will not rotate if the device does. I am currently working on a solution to this but so far here is a question that can show you how to add the view from another nib file to a uiview control.
If I follow I think you will need to:
Create a UIView sub class with associated xib
ExampleView.h
ExampleView.m
ExampleView.xib
Set up a property to contain the View hierarchy (everything you want to be hooked up in Interface builder)
ExampleView.h
#property (nonatomic, retain) IBOutlet UIView *exampleView;
ExampleView.m
#synthesize exampleView = _exampleView;
In the ExampleView.m you need to add:
- (void)awakeFromNib
{
[super awakeFromNib];
[[NSBundle mainBundle] loadNibNamed:#"ExampleView" owner:self options:nil];
[self addSubview:self.exampleView];
}
You use awake from nib so you can use this sub class in Interface Builder. If you also want to instantiate it in code you need to hook up the xib in the init method. In this case I would probably extract the nib loading like so:
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self loadNibIntoView];
}
return self;
}
- (void)awakeFromNib
{
[super awakeFromNib];
[self loadNibIntoView];
}
- (void)loadNibIntoView
{
[[NSBundle mainBundle] loadNibNamed:#"ExampleView" owner:self options:nil];
[self addSubview:self.exampleView];
}
In the ExampleView.xib file make sure to hook up your IBOutlet UIView *exampleView to the base view.
Now in any xib file where you want to use your custom view simply drag it into your window and change the class to your subclass. This is how I got it working I look forward to some people suggesting improvements.
can u tell me what u want to do? if u want to change orientation then first u declare a bool en type variable in app delegate file then define in app delegate.m file if orientation change then detect and make Boolean type variable true for landscape and false for portrait. this process use for next all views. and u want u execute nib in main view controller then u have two ways one is dynamically and other by interface builder. in interface builder u Select navigation controller and drop in main window file . after that u change the view of navigation controller's view by press cmd+4 and select view which u want to display first.
-(IBAction)btnSubmit_click{
UIDeviceOrientation orientation = [[UIDevice currentDevice]orientation];
if (orientation == UIDeviceOrientationLandscapeLeft) {
// Do stuff
}
else if (orientation == UIDeviceOrientationLandscapeRight) {
// Do stuff like [self setCordinateLandscape];
}
}
-(BOOL)shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation) interfaceOrientation
{
// Return YES for supported orientations
//set as per requirements ====>>
return (interfaceOrientation == UIDeviceOrientationLandscapeRight);
// Or return TRUE;
}

Add an existing view with a nib file in another view through Interface Builder

I have a nib file say TestView.xib. I added some components to it.
Now I created another nib file AnotherTestView.xib
I want to add the view of TestView.xib into AnotherTestView.xib using interface buidler, so that I dont need to add the same components from TestView again. They are like basic components for all my views.
Is there any way to do that. Like can we set the nib file name for a UIView in IB. Or how can we add this existing view which has a nib file into another nib file.
I wrote up how we embed custom-view Nibs inside other Nibs in a longish blog post. The crux is overriding -awakeAfterUsingCoder: in your custom view, replacing the object loaded from AnotherTextView.xib with the one loaded from the "embedded" Nib (TestView.xib).
Something along these lines:
// TestView.m
- (id) awakeAfterUsingCoder:(NSCoder*)aDecoder {
BOOL theThingThatGotLoadedWasJustAPlaceholder = ([[self subviews] count] == 0);
if (theThingThatGotLoadedWasJustAPlaceholder) {
// load the embedded view from its Nib
TestView* theRealThing = nil;
NSArray* elements = [[NSBundle mainBundle] loadNibNamed: NSStringFromClass([TestView class])
owner: nil
options: nil];
for (id anObject in elements) {
if ([anObject isKindOfClass:[TestView class]]) {
theRealThing = anObject;
break;
}
}
// pass properties through
theRealThing.frame = self.frame;
theRealThing.autoresizingMask = self.autoresizingMask;
[self release];
self = [theRealThing retain];
}
return self;
}