AppDelegate can't add subView - objective-c

Since appDelegate does not have a view, just window, its hard to figure out how to load a view from it. My problem has for long been that when didReceiveLocalNotification fires i cant load a new view with that event. I have been working around it til the point that i must do something about it. When i tries to addSubview, xcode gives me the error:
Receiver tupe 'UIWindow' for instance messages does not declare a method with selector 'addSubView'
for this: (at [self.window addSubView:view];)
screwLightBulbViewController *view = [screwLightBulbViewController newMyView];
[self.window addSubView:view];
I understand that the appDelegate file does'nt have a addSubview but i want to switch to a particular view when it fires.
I have tried many other ways, like calling a function in screwLightBulbViewController and make a view from that. My function in the viewController now looks like this:
+(id)newMyView
{
UINib *nib = [UINib nibWithNibName:#"MyView" bundle:nil];
NSArray *nibArray = [nib instantiateWithOwner:self options:nil];
screwLightBulbViewController *me = [nibArray objectAtIndex: 0];
return me;
}
any help in any way would be realy appreciated and thanks for you time. :)

It's addSubview not addSubView:. UIWindow is a subclass of UIView.
Adding a view directly as a subview to the window is not usually recommended, so instead you should try and add the view as a subview to the top controller view. If you can spare some time you should look over the view programming guide and view controller programming guide, it will be useful in the future.

Related

Confusion with UINavigationControllers in SplitViewController

I am setting up an iPad app that uses a SplitViewController. In my app delegate I have the following in didFinishLaunchingWithOptions:
UISplitViewController *splitViewController = (UISplitViewController *)self.window.rootViewController;
UINavigationController *leftNavController = [splitViewController.viewControllers objectAtIndex:0];
LeftViewController *leftViewController = (LeftViewController*)[leftNavController topViewController];
DetailViewController *detailViewController = [splitViewController.viewControllers objectAtIndex:1];
NSLog(#"Detail View Ctrl >> %#", [detailViewController class]);
When I run the app, the NSLog statement returns "UINavigationController" when DetailViewController is actually a subclass of UIViewController. However, in XCode, code completion shows all the methods that are implemented in the DetailViewController subclass. Any ideas? Thanks!
I think your DetailViewController is actually embedded inside a UINavigationController, and your fourth line is in error. Take a look instead at the topViewController for the second view controller inside your split view controller, much like you do for the LeftViewController.
The reason Xcode is continuing to suggest completion for DetailViewController methods is because you've given it that type. Code completion doesn't rely on runtime behavior (how could it?) – instead, it relies on static analysis of the code that you type. If you tell Xcode that something is a DetailViewController, it'll believe you and autocomplete based on that information.

How to addsubview to a view on class1 from class2?

I'm trying to do a really simple thing - I've got a main Xib file for the whole app and another Xib file for a small view.
I want the small view (Xib called "additionalView.xib") to appear in the first Xib ("ViewController.xib").
I have succeeded to do so in the "ViewController.m" but I want more - I want to do it from "additionalView.m"
There is a method I created called "openView:" in "additionalView.m" and it looks like this:
-(IBAction)openView:(id)sender
{
ViewController *vc = [[ViewController alloc] init];
NSArray *nibObjects = [[NSBundle mainBundle] loadNibNamed:#"additionalView" owner:self options:nil];
UIView *nibView = [nibObjects objectAtIndex:0];
[vc.view addSubview:nibView];
}
The method is being called and the lines are being read by the debugger - but nothing happens.
No crash - No error - No small view in bigger view.
Why is that?
I know that the last line is probably what's
screwing everything up but i don't know how to put it correctly.
Your problem is that ViewController *vc = [[ViewController alloc] init]; creates a new view controller. Because it's new, it's not the one that already exists in the view controller hierarchy that's managing the display.
Your method needs to access the existing view controller. How it does that depends on your app's structure and which object has a reference to the original controller object.
Try
[self.view addView:view.vc];
However, I'm not sure what is you view structure here. You say your -(IBAction)openView:(id)sender is in your "additionalView.m", but it is not the main view controller, correct? You need to do this in the main controller, so basically move the openView: method to your ViewController.m
And you normally need a separate view controller for each view to keep things neat and separate, so the additionalView.m should be an instance of UIViewController, which you can then create from your main view as follows:
-(IBAction)openView:(id)sender
{
AdditionalView *vc = [[AdditionalView alloc] initWithNibName:#"additionalView"];
[self.view vc.view];
}
You have options ... First you don't need to create a view controller vc if you just need the view . Create a uiview and add it .
Option 1: pass a ref to the app vc as suggested above and then :
[appVC.view addsubview:additionalView]
This will add it to main.
Use a view controller manager / ref in the app delegate that you can refer to as delegate and add your view to the current showing view.
Hope this helps

Is this a correct way to add/remove views?

Lets say that I have 4 view controllers (call them FirstView,SecondView,ThirdView,FourthView) which are created programmatically and all are in separate files:
In AppDelegate.m didFinishLaunchingWithOptions method I have these lines of code
self.rootViewController = [[rootViewController alloc]initWithNibName:#"rootViewController" bundle:nil];
self.window.rootViewController = self.rootViewController;
In rootViewController.m loadview method I have
self.view = [[UIView alloc]initWithFrame:[UIScreen mainScreen].applicationFrame];
self.firstView = [[FirstView alloc]init];
[self.view addSubview:self.firstView.view];
That code works fine - first view is displayed.
Let's continue
In FirstView.m switchViews method
NOTE: Please see the comments in code
self.secondView = [[SecondView alloc] initWithNibName:#"SecondView" bundle:nil];
// I think here secondView is added to rootViewController - right ?
[self.view.superview addSubview:self.secondView.view];
// Here first view is removed from rootViewController - right ?
[self.view removeFromSuperview];
Here is how I add/remove views.
Is this approach correct?
Can you recommend a better solution?
I have read about UINavigationController, but I don't think it could be a solution in this case.
You say:
I have 4 views (call them FirstView ...
Then you say:
[self.view addSubview:self.firstView.view];
Which makes me think that FirstView isn't actually a UIView - as you claim it is. Instead, it's probably a UIViewController - a different beast altogether.
If my suspicion is correct - then you are "off-track" so to speak.
Going beyond that to your sample code snippet:
self.secondView = [[SecondView alloc] initWithNibName:#"SecondView" bundle:nil];
// I think here secondView is added to rootViewController - right ?
[self.view.superview addSubview:self.secondView.view];
// Here first view is removed from rootViewController - right ?
[self.view removeFromSuperview];
This is definitely not a great idea. Here's why:
First: your view controller doesn't explicitly "know" anything about the superview you are so casually inserting and removing subviews to/from - so it shouldn't do that. You may, alternatively, create your own view and insert/remove subviews from that - which would not only be perfectly acceptable but also common practice.
Second: if these are actually UIViewControllers like I think they are - then you are not properly handling hooking them up to the UIViewController event chain - which means methods on these subclasses like viewDidAppear: or viewDidUnload will not fire.
From what I see in your code, UINavigationController seems like it would help. If you don't want a navigation bar, you can definitely hide it, but the methods in UINavigationController should help you with switching views.
If your views only need to display temporarily, you could also use Modal View controllers. An example of Modal View controllers can be found here.
If you haven't already, check out the View Controller Programming Guide from Apple.

Design an NSView subclass in Interface Builder and then instantiate it?

So I have an NSTabView that I'm dynamically resizing and populating with NSView subclasses. I would like to design the pages in IB and then instantiate them and add them to the NSTabView. I got the programmatic adding of NSView subclasses down, but I'm not sure how to design them in IB and then instantiate them.
I think I got it. Let me know if this is not a good thing to do.
I made a new xib file, set its File's Owner to be an NSViewController and set its "view" to the custom view I designed in the xib.
Then you just need:
NSViewController *viewController = [[NSViewController alloc] initWithNibName:#"MyViewXib" bundle:nil];
NSView *myView = [viewController view];
#toastie had a really good answer. Mine is similar, but requires a bit more explanation.
Let's say you've already got a controller object and you don't want to instantiate a new controller object just to get at a view, and let's say that you're going to need multiple copies of this view (for example, you've designed a custom UITableViewCell in IB and you want to instantiate it again and again from your UITableViewController). Here's how you would do that:
Add a new IBOutlet to your existing class called "specialView" (or something like that). It may also be helpful to declare it as a (nonatomic, retain) property.
Create a new view xib called "SpecialView", and build the view however you like.
Set the File's Owner of the view to be your controller object.
Set the specialView outlet of File's Owner to be the new view.
Whenever you need a new copy of the view in your code, you can simply do the following.
(gratuitous text to get formatting working properly)
NSNib * viewNib = [[NSNib alloc] initWithNibNamed:#"SpecialView" bundle:nil];
[viewNib instantiateNibWithOwner:self topLevelObjects:nil];
[viewNib release];
NSView * myInstantiatedSpecialView = [[[self specialView] retain] autorelease];
[self setSpecialView:nil];
Yes, it's a bit more code than other ways, but I prefer this method simply because the view shows up in the designated IBOutlet. I retain and autorelease the view, because I like to reset the outlet to nil once I have the view, so it can be immediately ready to load a new copy of the view. I'll also point out that the code for this is even shorter on the iPhone, which requires one line to load the view, and not 3 (as it does on the Mac). That line is simply:
[[NSBundle mainBundle] loadNibNamed:#"SpecialView" owner:self options:nil];
HTH!

Why is this iPhone program not calling -loadView?

I am trying to work my way through basic iPhone programming and I have a good basic understanding of how Interface Builder works, so I decided to try my hand at doing the views programmatically. I have gone through the ViewController Apple guide and searched everywhere and I cannot seem to find a solution to my problem. This leads me to believe it is a very simple solution, but I am just really banging my head against the wall. Basically all I am trying to do is create a view that gets main window as a subview. I know that if self.view is not defined then the loadView method is supposed to be called, and everything is supposed to be set up there. Here is the current state of my code:
The delegate:
- (void)applicationDidFinishLaunching:(UIApplication *)application {
StartMenuViewController *aViewController = [[StartMenuViewController alloc] init];
self.myViewController = aViewController;
[aViewController release];
UIView *controllersView = [myViewController view];
window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
[window setBackgroundColor:[UIColor redColor]];
[window addSubview:controllersView];
[window makeKeyAndVisible];
}
The view controller:
- (id)init {
if (self = [super init]) {
self.title = #"Start Menu";
}
return self;
}
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView {
UIView *startView = [[UIView alloc] initWithFrame:[UIScreen mainScreen].applicationFrame];
[startView setAutoresizingMask:UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth];
[startView setBackgroundColor:[UIColor greenColor]];
self.view = startView;
[startView release];
}
Thanks for the help in advance!
Are you sure that you're inheriting from UIViewController and not overriding the implementation of - (UIView*)view?
EDIT: More info:
UIViewController has a special implementation of the "-(UIView*) view" message so that when it's called, the loadView method is called if the view member variable is not set. So, if you provide an implementation of "- (id)view" in your subclass, (or a property named view) it will break the auto-calling of "- loadView".
Just to document a "loadView is not called" case:
I wrote a 2 UITableViewController(s) to handle detail data for a master ViewController. Since the devil was in #2, I made a simple UITableViewController for #1, and referenced it in the XIB for the "master" ViewController.
When I was done with #2, I could simply copy the code to #1, remove the complicated code, and go on with life.
But to my dismay and several days work, no matter what I did, viewLoad was not being called for my simple #1 UITableViewController.
Today I finally realised that I was referencing the UITableViewController in the XIB to the master ViewController program. - and of course, loadView was never being called.
Just to help some other dork that makes the same mistake....
Best Regards,
Charles
viewDidLoad only if the view is unarchived from a nib, method is invoked after view is set.
loadView only invoked when the view proberty is nil. use when creating views programmatically. default: create a UIView object with no subviews.
(void)loadView {
UIView *view = [[UIView alloc] initWithFrame:[UIScreen
mainScreen].applicationFrame];
[view setBackgroundColor:_color];
self.view = view;
[view release];
}
By implementing the loadView method, you hook into the default memory management behavior. If memory is low, a view controller may receive the didReceiveMemoryWarning message. The default implementation checks to see if the view is in use. If its view is not in the view hierarchy and the view controller implements the loadView method, its view is released. Later when the view is needed, the loadView method is invoked
again to create the view.
I would strongly recommend you use interface builder for at least your initial Window/View.
If you create a new project in XCode you should be able to select from one of many pre-defined iPhone templates that come with everything setup.
Unless I am reading this wrong, you did not associate any view with the the controller's view property like this
myViewController.view = controllersView;
So as far as Cocoa is concerned the view you are setting in the window has no controller to call loadView on. loadView is a View controller, not view, method. The view you assign to the window is not associated with any view controller. So your view controller loadView method is never called. Get it? The view you are trying to display, has no view controller associated with it.
When you use interface builder to create views you can link the UIView object you created in IB to the view property in the controller in IB which the framework automatically
But if not done in IB you have to set it