Creating a new ViewController and xib for programmatic display (with addSubview) - iphone

I am writing a library to be used by developers for the iPhone (similar to the way that OpenFeint is implemented) and I am trying to create a ViewController with an associated XIB so that I can instantiate it in my code with
SplashScreenViewController *splashScreenViewController = [[SplashScreenViewController alloc] init];
UIWindow *topApplicationWindow = [self getTopWindow];
[topApplicationWindow addSubview:splashScreenViewController.view];
However, while this works with simple controls (UIButtons, etc), nothing shows up with my SplashScreenViewController. SplashScreenViewController is very simple:
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#interface SplashScreenView : UIViewController {
}
#end
and the implementation is empty. In my View XIB (SplashScreenView.xib), I have tried setting the File's Owner's class to SplashScreenViewController which didn't work, then I tried it the way I've seen it done in OpenFeint which is to add a View Controller in IB and make the main UIView a child of it and make it of class SplashScreenViewController instead. That also does not work (does not display).
I'm wondering if anyone has a good idea for what I might be missing, or if someone can recommend a walkthrough for creating new ViewControllers the way that I'm attempting to.
Thanks!

Try 2 things :
Call initWithNibName not just init. Maybe the OpenFeint you were talking about were overriding the init to call initWithNibName , that's why you don't see it.
Set SplashScreenViewController as your file owner, and connect his view outlet to your
view in IB.
Hope it helps.

Instead of [splashScreenViewController alloc], try [SplashScreenViewController alloc]. I'm surprised you didn't get a compiler warning.

Related

My objects in storyboard don't link correctly with the code

I am trying to use storyboards in my application. I began well, I have added two view controllers with a button to go from the first to the second.
The problem is in this second view controller: the objects I add on it and link with the code do not work. When I set a breakpoint in the view controller code, the 'self.property' is set to nil, whereas it should be instantiated by the storyboard.
I have been looking for an answer for hours, and I really don't understand the problem, since all the rest seems to be good.
I have tried to write the property in the code (strong/nonatomic, nonatomic/retain and even weak/nonatomic), to link the object directly to the code so that it creates the property automatically, but I never get anything else than "nil" with breakpoints.
viewController.h:
#interface NMLoadingViewController : UIViewController
{
__weak IBOutlet UIProgressView *imageProcessingProgressView;
}
#property (weak, nonatomic) IBOutlet UIProgressView *imageProcessingProgressView;
#end
.m:
#synthesize imageProcessingProgressView;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
// Custom initialization
NSLog(#"INIT.");
}
(amont other lines of irrelevant code)
If I set the breakpoint to the "INIT." line, my imageProcessingProgressView is nil. I can't see a reason for that, I guess I have missed a very little detail...
(Note that I have tried this with other objects, like a UILabel, but it did not work either. Stranger, when I had two objects, one of them had an adress which was not nil, but still it was corrupted and did not show the right object.)
Edit: It was a lot of trouble for nothing... The problem is about the Variable View in XCode, which show my variable to "nil", whereas a log shows me a correct object...
Remove this...
{
__weak IBOutlet UIProgressView *imageProcessingProgressView;
}
...and make the property strong.
Change your log message to...
NSLog(#"INIT: %#", self.imageProcessingProgressView);
...and see if you still have a problem. If you do, then take another look at your storyboard connections.
Make sure NMLoadingViewController is the class on your viewController
First try out the answer by #Eric because I do believe that is the real issue.
Also, make sure that you are actually using the interface builder to hook the controls back to the view controller. This is done by dragging a line from the control back to the property of the view controller.

UIWindow UIView addSubview issue

Every video tutorial and book I have read displays the following code to add a UIView to the UIWindow.
[window addSubview:self.viewController.view];
My understanding of the above code is that a "View" (which is an instance of a UIView) is added to the window (Which is an instance of UIWindow). Let me break it down (According to my understanding):
window (UIWindow)
addSubview (method to add a View to a window)
Self.viewController.view (simply returns an instance of a "view" which is already instantiated within the UIViewController class.
The first problem I have is that I could not find the method "addSubview" in the UIWindow class reference document on apples site. However somebody kindly pointed out to me that UIWindow inherits addsubview method from UIView. thats all fine, but why do all the book and online documents state that the addsubview method adds a view to the window - but how can that be? really confused. Can somebody please explain step by step what this code is doing? If UIWindow inherits the addsubview method of UIView then how can it go back up the inheritance tree? really lost. What I really need is small example code with diagrams of what is happening step by step. would be REALLY greatfull. many thanks
Think of a window as a view that's associated directly with a screen or drawing object.
In the above example window.view is not correct. a window does not contain a view, it is a view with additional behavior.
Assuming that you are loading a UIViewController from a NIB file, the view associated with the viewController will be instantiated by accessing the view. So ...
You might see code like
MyViewController *vc = [MyViewController alloc]initWithNibName:#"MyNibFile" bundle:nil]autorelease];
[window addSubView:vc.view];
[window makeKeyAndVisible];
View is simply a super class of Window so any public view method is available to you.
Generally the window in your AppDelegate object is instantiated when the MainWindow.xib file is loaded.
You should see something like
#property(nonatomic, retain) IBOutlet UIWindow *window;
in your AppDelegate header file . (The IBOutlet directive tells the initialize the window object when the nib file is loaded.
Just remember, a UIWindow is simply a UIView with additional behaviors and data.
Hope this helps.
"However somebody kindly pointed out to me that UIWindow inherits addsubview method from UIView. thats all fine, but why do all the book and online documents state that the addsubview method adds a view to the window - but how can that be? really confused. Can somebody please explain step by step what this code is doing? If UIWindow inherits the addsubview method of UIView then how can it go back up the inheritance tree?"
That's it. I think you are not understanding what inheritance is. The metaphor is "is a". A UIWindow "is a" UIView. It has everything a UIView has, and more. One thing a UIView has is the ability to addSubview. Therefore a UIWindow has that ability too. It doesn't need any other UIView to do it for it. It is a UIView. It can do it itself.
try
[window.view addSubview:self.viewController.view];
That is off the top of my head, so it may not be completely accurate.

iPhone Subclassing view controller and IBOutlet UITableView

I have the following problem. I've created a ViewController pretty much like the above
#interface MyViewController : UIViewController {
IBOutlet UITableView *myTableView;
}
#property (nonatomic, retain) IBOutlet UITableView *myTableView;
I've linked myTableView on the Interface Builder to the matching nib's UITableView. and I've subclassed MyViewController to create YourViewController as so:
#interface YourViewController : MyViewController {
}
And then I load from a TabBarController the YourViewController on a tab item. Although I can see that MyViewController is indeed invoked at the end, no table view is displayed on the emulator.
I've tried debugging the MyViewController and it appears the the IBOutlet is nil.
Why is that?
I have encountered major issues with inheritance and IBOutlets and IBAction. I advise you to avoid that, and create shared stuff in another way.
I was hit hard by bugs when getting memory warnings for instance. Outlets and actions didn't get reconnected properly when they were defined in base class vs derived class.
Probably MyViewController's nib file is not loaded at all. Are you using for YourViewController a specific nib file? and in which way are you creating YourViewController.
Can you also try to define an "awakeFromNib" method in YourViewController and then from it call [super awakeFromNib] ?
However to understand your issue you must clearly explain how you load objects and if and where you use Nibs?
If you add it dynamically using code then only it will work. Not using Nib.
the UITableView (ie. your myTableView) needs delegates for data source and and its control.
And your controller needs a link to the Table view in the xib.
declare table delegate protocols in the interface section of your controller.
using IB, link the TableView in your xib to owners file:delegates.
using IB, link the file owner myTableView to the tableView in the xib.
I hope it will help.
Assuming that you have your whole navigation stack in MainWindow.xib
Open MainWindow.xib
Select YourViewController (Or whatever your controller that is subclassing UITableViewController is called)
Select Attributes Inspector
Ensure that the 'NIB Name' property has your correct YourViewController (Or whatever the name) selected
I had this exact same issue, this solved it for me.

Possible to use UIActionSheet from Application Delegate?

I have a common UIActionSheet which I use across about 10 different view/view controllers. I'm wondering if it's possible to use UIActionSheet from the app delegate in order to prevent code duplication?
So far my attempts to use an action sheet from the delegate haven't worked, I suspect my problem lies when calling the showInView method - do I need to instantiate an object of my view controller then use viewController.view here? If so how can I then tell which view called the action sheet method from the delegate?
I didn't try the approach proposed by c_phlat, but I wonder to what self.view is mapped.
I did manage to do it like this:
[actionSheet showInView:window];
it works just as well.
I was having the same problem, and I recently figured out a way to fix it in my app. The key for me was to make my app delegate class an extension of UIViewController rather than NSObject. (I think UIViewController is a subclass of NSObject anyway, so this shouldn't affect your app too much.)
In other words, change the main implementation line in your app delegate interface file from something like this:
#interface YourAppDelegate : NSObject <UIApplicationDelegate, UIActionSheetDelegate> {
To this:
#interface YourAppDelegate : UIViewController <UIApplicationDelegate, UIActionSheetDelegate> {
You should now be able to use the showInView: method with your action sheet within your app delegate implementation:
[yourActionSheet showInView:self.view];

iPhone Views at Runtime?

I am new to the iPhone SDK and am trying to create 3 views and switch between them. Data will come from a server and I will basically be showing 1 view and caching the other two. So far I am just trying to create a view and display it at run-time. My code is listed below. It shows only a blank screen and I think I am missing a key concept. Any Help?
#import <UIKit/UIKit.h>
#import "ImageViewController.h"
#interface Test5ViewController : UIViewController
{
IBOutlet UIView *rootView;
ImageViewController *curImage;
ImageViewController *nextImage;
ImageViewController *prevImage;
}
#property(nonatomic,retain) IBOutlet UIView *rootView;
#property(nonatomic,retain) ImageViewController *curImage;
#property(nonatomic,retain) ImageViewController *nextImage;
#property(nonatomic,retain) ImageViewController *prevImage;
#end
and
- (void)loadView
{
self.curImage = [[ImageViewController alloc]initWithNibName:#"ImageView" bundle:[NSBundle mainBundle]];
UIImage *pic = [UIImage imageNamed:#"baby-gorilla.jpg"];
[self.curImage assignImage:pic];
self.rootView = self.curImage.view;
}
and
#import <UIKit/UIKit.h>
#interface ImageViewController : UIViewController
{
IBOutlet UIImageView *image;
}
-(void)assignImage:(UIImage *)screenShotToSet;
#property(nonatomic,retain) IBOutlet UIImageView *image;
#end
Welcome to the iPhone SDK!
In general, there are two ways to get any view displayed.
First, and most commonly, you use a NIB file created by the Interface Builder. This is usually the easiest way to get started and I would recommend it for what you're trying to do here. It's too lengthy to describe all the steps you need to do for what you have here, but basically start in xcode by creating a new file and selecting "user interfaces" and choose View XIB. This will create a basic NIB file (they're called NIBs rather than XIBs for historical reasons). The first step in interface builder is to change the class name of the "File's Owner" to your UIViewController subclass (Test5ViewController). You can then drop anything that IB will allow into the view window or even replace the pre-supplied view object with one of your own. And here's the trick: make sure the view outlet (supplied by the UIViewController superclass) is connected to a view. Once this is done, this view will be automatically loaded when your NIB is loaded. You can then just put your UIViewController subclass (Test5ViewController) in your MainWindow.xib NIB file to get it automatically loaded, and you're in business.
Now, the way you're doing it here is the second way. Some people like to code this way all the time and not user interface builder. And while it's definitely necessary sometimes and always more flexible, it makes you understand what is happening a bit better. There may be other things, but the main thing you're missing is that in your code above, you have nothing that is adding your view into the view hierarchy. You need to check first that you have an UIApplicationDelegate subclass and it needs to load your "root" UIViewController class. All initial project creation types in xcode do this (except Window-based application). It is code like:
[window addSubview:rootController.view];
Once this is done, if your view controller wasn't loaded by the NIB (described briefly above), your loadView method will be called, expecting you to build your own view hierarchy. Above, you created the view(s), but failed to put them in a hierarchy. You need something like:
[self.view addSubview:curImage.view];
No view will be rendered until added to the view hierarchy. Make sure to look up the UIView class in the documentation and understand the variety of ways to add and remove views to the view hierarchy.
A couple things I should warn you about:
* your code above is leaking. You need to review how objective-C properties work. There's lots on this site about it. More than I have time to write about here.
* don't create a rootView property in the case you have here. There already is one in the superclass (UIViewController). It's just 'view'. Use that for saving your root view.
I hope this helps you get started. It can be bewildering at first, but you'll soon get it going! I recommend building and rewriting and rebuilding a lot of sample code before you do your "real" application. The SDK has many great samples.