Add view to the top view controller - objective-c

Im trying to add a UIView to the UIView that is currently showing.
This is the code I've come up with:
UIWindow *window = [UIApplication sharedApplication].keyWindow;
UINavigationController *nav = window.rootViewController;
UIViewController *viewController = [[nav viewControllers]lastObject];
NSLog(#"La clase: %#", [viewController class]);
[viewController.view addSubview:self.infoMsg];
The problem is that I dont see that UIView, the value of the variable viewController is correct, but I don't see the view added on that view...
Thanks
[EDIT]
I just checked and If for example instead of add as a subview infoMsg which is a UIView that I have syntesized, and I add a UIView that I create just before adding it adds correctly why is that? why can't I add an attribute of my object?

You have to still create the view before adding it, no matter if it's a property or just a local variable. I don't see where you initialize self.infoMsg. It's probably nil.
Try this:
NSLog(#"%#", self.infoMsg == nil ? #"It's nil" : #"It's not nil");
If it's nil, that that's your problem.

Related

UIView Subclass backed by xib with Size Classes wrong frame

I am working on a project for iOS 7.0+ with a storyboard, using Size Classes with AutoLayout and I'm using a UIView subclass backed by a xib file of the same name.
What I'am trying to do is I'am instantiating a UIView from xib programmatically and adding it to a ViewController from a Storyboard. This ViewController has AutoLayout up and running but the UIView I am adding doesn't respect the frame of the ViewController.
I'm instantiating my UIView subclass like this:
tabBarView = [[SHDTabBarView alloc] initWithFrame:CGRectMake(0, self.view.height-50, self.view.width, 50)];
[self.view addSubview:tabBarView];
And inside the subclass I'm using a set up of creating a UIView IBOutlet called container to instantiate it form code like this:
-(id)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
if (self == nil) return nil;
[self initalizeSubviews];
return self;
}
-(id)initWithCoder:(NSCoder *)aDecoder{
self = [super initWithCoder:aDecoder];
if (self == nil) return nil;
[self initalizeSubviews];
return self;
}
-(void)initalizeSubviews{
NSString *nibName = NSStringFromClass([self class]);
UINib *nib = [UINib nibWithNibName:nibName bundle:nil];
[nib instantiateWithOwner:self options:nil];
//Add the view loaded from the nib into self.
[self addSubview:self.container];
}
This is how my xib looks in the Interface Builder (notice the width of the canvas is 320 px):
And that's how it looks on the iPhone 6 (notice how it's getting cut off from the right side):
I've tried to use a multitude of solutions, including doing it all in code with an open-source solution PureLayout, using a manual constraint set up, etc.
None of my findings seem to work right. Ideally, I want to set up everything in Interface Builder, then just add the view to the superview of the ViewController with according frame and let AutoLayout do its magic.
How should I approach this task? Any advices are more than welcome.
Try to set the frame of your subview in the viewDidLayoutSubviews(). Looks like you init your subview before view fully layouted

How do I get acces to the parent view?

I'm trying to acces the storyboard from code to be able to use this line:
DetailViewController *detail = [self.storyboard instantiateViewControllerWithIdentifier:#"detail"];
I use that in my mapview and listview, but want to use it somewhere else to.
The problem is that this view, is a subview of another view.
It's set up as followed:
thisBigView is a view I added in the storyboard and it's is ThisBigViewController
In storyboard I added another view to that view, let's call it thisSmallView. The class is set to ThisSmallView.
ThisSmallView is a custom view where I generate buttons dynamically in on the view. These buttons call the following action:
-(void) radarEventClick:(UIButton *)sender{
SingletonManager *sharedManager = [SingletonManager sharedManager];
DetailViewController *detail = [self.storyboard instantiateViewControllerWithIdentifier:#"detail"]; // PROBLEM 1
Event *a;
for(int i = 0; i < [sharedManager.eventsManager count]; i++){
if(sender.tag == ((Event*)([sharedManager.eventsManager objectAtIndex:i])).id_nr){
a = [sharedManager.eventsManager objectAtIndex:i];
break;
}
}
[detail setEvent:a];
[self.navigationController pushViewController:detail animated:YES]; // PROBLEM 2
}
This is code I'm using in my mapviewcontroller to respond to annotationdisclosure clicks, and want to use it here to, but I have 2 problems!
PROBLEM 1: Because thisSmallView is a subview of anotherview, it doesn't have direct access to the storyboard and don't know how to get that access.
PROBLEM 2: thisBigView is embed in a navigationcontroller, but again, I don't know who to access thisBigView, so I can't access the navigationcontroller.
(I think if I could solve problem 2, I would automatically be solving problem 1 to?)
-- EDIT: what I tried --
DetailViewController *detail = [self.superview.storyboard instantiateViewControllerWithIdentifier:#"detail"];
But then I just get 'property storyboard not found on object of type UIView*'
superview
[smallView superview]
http://developer.apple.com/library/ios/documentation/uikit/reference/uiview_class/uiview/uiview.html#//apple_ref/occ/instp/UIView/superview
Add the subview as a property of the superview in interface builder (control-drag to the header file). Then add a UIViewController property to the subview. In the superview's code then do
nameOfSubView.superViewPropertyName = self;

Split View Popover Delegate Method Not Called

EDIT 2: I tried pointing to the view controller using the following code:
UIStoryboard *iPadStoryboard = [UIStoryboard storyboardWithName:#"iPadStoryboard" bundle: nil];
GTGiftsIPadViewController *giftsIVC = (GTGiftsIPadViewController *)[iPadStoryboard instantiateViewControllerWithIdentifier: #"giftsTableViewControllerId"];
[giftsIVC setGiftsDelegate:self];
NSLog(#"%#", giftsIVC);
NSLog(#"%#", [[[[[[self parentViewController] parentViewController] childViewControllers] objectAtIndex:0] childViewControllers] objectAtIndex:0]);
However, this outputs:
2012-06-02 14:28:47.148 Gift Manager[3958:707] <GTGiftsIPadViewController: 0xc6b9980>
2012-06-02 14:28:47.152 Gift Manager[3958:707] <GTGiftsIPadViewController: 0xc6a16d0>
Meaning that giftsIVC is not pointing to the proper view controller. It has to point to the view controller given by [[[[[[self parentViewController] parentViewController] childViewControllers] objectAtIndex:0] childViewControllers] objectAtIndex:0]. However, I cannot use this code because it is does not work for both the portrait and landscape view.
This seems like something that should be very straight forward to do, but I'm pulling my hair out trying to figure this out! It's driving me crazy!
EDIT: I figured out the problem and it has to do with how I'm setting the delegate. This is my (poor) way of setting the delegate:
[[[[[[[self parentViewController] parentViewController] childViewControllers] objectAtIndex:0] childViewControllers] objectAtIndex:0] setGiftsDelegate:self];
Basically [[[[[[[self parentViewController] parentViewController] childViewControllers] objectAtIndex:0] childViewControllers] objectAtIndex:0] is just referencing my table view controller. Is there an alternative way I could write this bit of code to exclude the [[[[[[[self parentViewController] parentViewController] childViewControllers] objectAtIndex:0] childViewControllers] objectAtIndex:0] portion?
I have been trying to avoid creating my own delegate protocols, mainly because I'm not very comfortable with the idea of a delegate yet. Anyway, I went ahead and created one yesterday because I really needed it, and to it worked very well! I have a split view controller that displays two controllers when the iPad is in landscape mode (one table view and a detail view for the objects in the table view). The purpose of the delegate protocol is to allow the table view to update the detail view when an object in the table view is selected. This works in landscape mode; however, in portrait mode I only have one view controller and a button to display a popover that presents the table view (this is almost identical to the Notes app on the iPad).
My problem is that when in portrait mode and a object in the popover view table is selected the didSelectGift method is not called; however, in landscape mode it is. See capitalized comments below.
This is my code for the delegate protocol:
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>
#import "GTAddIPadViewController.h"
#class GTGift, GTGiftCell;
#protocol GTGiftsIPadViewControllerDelegate;
#interface GTGiftsIPadViewController : UITableViewController
#property (nonatomic, assign) id <GTGiftsIPadViewControllerDelegate>giftsDelegate;
#property (nonatomic, strong) IBOutlet UITableView *giftsTable;
#end
#protocol GTGiftsIPadViewControllerDelegate <NSObject>
- (void)didSelectGift:(GTGift *)selectedGift;
#end
didSelectGift is called in the GTGiftsIPadViewController
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
GTGift *gift = [[[GTGiftStore sharedStore] allGifts] objectAtIndex:[indexPath row]];
[giftsDelegate didSelectGift:gift]; //THIS FUNCTION IS NOT CALLED (TESTED BY PUTTING AN NSLOG INSIDE IT)
NSLog(#"%#", [gift name]); //THIS OUTPUTS PROPERLY THEREFORE TABLEVIEW:DIDSELECTROWATINDEXPATH: IS CALLED
}
The delegate is set the viewDidLoad method in a view controller called GTDetailIPadViewController
The didSelectGift method is implemented in the GTDetailIPadViewController:
- (void)didSelectGift:(GTGift *)selectedGift
{
[self setDetailGift:selectedGift];
[self populateTable];
}
(populateTable is a method that uses the instance variable of detailGift and populates the detail view with these values)
I really cannot understand why it works perfectly when the table is presented in the split view but does not work when it is presented in the popover view. Any help would be really appreciated and I hope I have made my problem clear! Thank you!
So, this code:
[[[[[[self parentViewController] parentViewController] childViewControllers] objectAtIndex:0] childViewControllers] objectAtIndex:0]
to reference to your table view controller... that's a bit crazy :-)
Also, I don't think delegate is the way to go here..
If you created a standard master/detail split view project in XCode, the master controller (the table view controller), should have a pointer to the DetailViewController (If I understand correctly, that would be the piece you call the delegate in your code).
So instead of declaring any delegate, you would just point directly to that detailViewController.
If for some reason, that pointer does not exist, you would want to create it, and whenever the master and detail are initialized, have something like this:
MasterViewController *masterViewController = [[MasterViewController alloc] initWithNibName:#"MasterViewController" bundle:nil];
DetailViewController *detailViewController = [[DetailViewController alloc] initWithNibName:#"DetailViewController" bundle:nil];
masterViewController.detailViewController = detailViewController;
(if your master and detail are not allocated in code like here, they should still both be accessible from a common place, let's say the app delegate, as IBOUtlets, you would then just use the third line of code, after making sure you have a property 'detailViewController' in your master's header)
That way, you should have the detailViewController referenced from the master view controller at all time, so you can call any method on it from the table view controller(master)
[detailViewController didSelectGift:selectedGift];

When do views get created?

I apologize in advance for the n00b question. I am just getting started w/ iOS!
I am trying to push a webViewController onto a navigation controller.
mudWebViewController *webViewController = [[mudWebViewController alloc] initWithNibName:nil bundle:nil];
[[webViewController webView] setDelegate:webViewController];
[[self navigationController] pushViewController:webViewController animated:YES];
But this doesn't seem to work, as I don't see any of the logs in the delegate messages.
If I set the delegate in the viewDidLoad: method, it works fine.
I guess the webView doesn't actually exist at that point, but why? If I initialize the controller, shouldn't the webView be initialized too?
Is viewDidLoad: the right place to be setting up this stuff?
initWithNibName should be not nil, since you obviously are using a nib file to build the view, else you have to create the view in code, which you don't
mudWebViewController *webViewController = [[mudWebViewController alloc] initWithNibName:#"webViewController" bundle:nil];
[[self navigationController] pushViewController:webViewController animated:YES];
Also any delegates should be set either from the Interface builder or from the view itself in the viewDidLoad delegate and not from the previous class, as the object might not been yet initialized in the code so it can fail to set the delegate properly.

Setting a ViewController's properties after instantiation

I'm creating an instance of a viewController, and then trying to set the text on of it's properties, a UILabel.
BoyController *boyViewController = [[BoyController alloc] initWithNibName:#"BoyView" bundle:nil];
NSString *newText = [astrology getSignWithMonth:month withDay:day];
boyViewController.sign.text = newText;
NSLog(#" the boyviewcontroller.sign.text is now set to: %#", boyViewController.sign.text);
[newText release];
I tried this, but it didn't work...
So I tried the following:
BoyController *boyViewController = [[BoyController alloc] initWithNibName:#"BoyView" bundle:nil];
UILabel *newUILabel = [[UILabel alloc] init];
newUILabel.text = [astrology getSignWithMonth:month withDay:day];
boyViewController.sign = newUILabel;
NSLog(#" the boyviewcontroller.sign.text is now set to: %#", newUILabel.text);
[newUILabel release];
But no avail..
I'm not sure why I can't set the text property of the UILabel "sign" in boyViewController..
The problem here is that the initializer does not actually load the nib file into memory. Instead, loading the nib is delayed until your application requests the view controller's view property. As such, your controller's sign property is null when you access it.
Manually requesting the controller's view property would make your example work...
BoyController *boyViewController = [[BoyController alloc] initWithNibName:#"BoyView" bundle:nil];
[boyViewController view]; // !!!: Calling [... view] here forces the nib to load.
NSString *newText = [astrology getSignWithMonth:month withDay:day];
boyViewController.sign.text = newText;
// and so on...
However, I'd guess that what you're really trying to do is create and configure your view controller before setting it free to do it's own thing. (Perhaps to display it modally, say.) Calling [... view] manually is not going to be a long-term solution.
Better is to set a separate property on your view controller for the label text and then implement viewDidLoad to assign it to the label:
#interface BoyViewController : UIViewController {
IBOutlet UILabel *label;
NSString *labelText;
}
#property(nonatomic, copy)NSString *labelText;
#end
#implementation
#synthesize labelText;
- (void)viewDidLoad
{
[label setText:[self labelText]];
}
// and so on...
#end
This has the added benefit of your label text being reset in case the view is purged during a low memory event.
Did you bind your outlets at Interface Builder?
It seems that you need to bind sign outlet of the first example into Interface Builder in order to actually set that text to whatever you want.
Once you bind your outlet to the actual UI component at Interface Builder, then you should be able to do something like:
NSString *newText = [astrology getSignWithMonth:month withDay:day];
[[boyViewController sign] setText:newText];
This is what you need to know about binding.
Your second example does not make sense at all to me.