Xcode 4 Universal Window Based App - Basic Query - ios

I'm struggling getting started with the Universal App template in Xcode 4.1. I'm following the basic principles set out by kotancode here. The problem is getting the relevant view controller to load. I will focus on the iPhone part as an example. I create a subclass of UIViewController without a XIB as my "master" view controller class (where shared code will go). I then subclass this to create the iPhone specific UIViewController class called BaseViewController_iPhone, this time with a XIB.
The iPhone specific app delegate the header is set to:
#import "TestAppDelegate.h"
#import "BaseViewController_iPhone.h"
#interface TestAppDelegate_iPhone : TestAppDelegate {
BaseViewController_iPhone *viewController;
}
#property (nonatomic, retain) IBOutlet BaseViewController_iPhone *viewController;
#end
and for the implementation I try to override the applicationdidfinishlaunchingwithoptions method.
#import "TestAppDelegate_iPhone.h"
#implementation TestAppDelegate_iPhone
#synthesize viewController;
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[self.window addSubview:viewController.view];
[self.window makeKeyAndVisible];
return YES;
}
-(void)dealloc {
[viewController release];
[super dealloc];
}
#end
This doesn't appear to work, it compiles fine and runs, but the new view controller and the corresponding XIB are not displayed (the original main window xib from the template is). I'm sure i'm missing something very simple, but i've spent a long time googling to no avail. Any help gratefully received.
Thank you.

Have you connected the ViewController in the app's delegate's XIB to your "BaseViewController_iPhone *viewController" ?
Are you sure the ViewController in the app's delegate's XIB is of the type BaseViewController?
Is the ViewController loading the correct XIB (check that in the app's delegate's xib)?
Check that and give some feedback.

Related

When adding UIView instantiated with an .xib to the Storyboard buttons don't work and background color can't be changed

I am working on an iOS project and wanted to include a UIView that is reused on multiple screens in the application (appearing at the bottom of different UIViews). I am using a storyboard for the UI work so far but created an .xib file to be used by the reusable view (playerView in code below).
The view gets added but the button I have added to the View is unresponsive, also my background color cannot be changed on the view. I have tried to set background color programmatically and in the .xib with no luck. Very weird symptoms and I tried to instantiate the view from #5 of this article and probably did something wrong. I dont fully understand everything in the article which makes me nervous - for instance my showSubclassedView method returns IBAction but I just call the function name in code and dont use a button (I did hook up the buttons in the view as the article described though).
Here is the code:
EventViewController.m (where I trry and add PlayerView)
#import "EventViewController.h"
#import "PlayerView.h"
#interface EventViewController ()
-(IBAction)showSubclassedView;
#end
#implementation EventViewController
-(IBAction)showSubclassedView
{
[PlayerView presentInViewController:self];
}
PlayerView.h (.h for reusable view)
#import <UIKit/UIKit.h>
#import "Utils.h"
#class PlayerView;
#protocol PlayerViewDelegate
-(void)playerViewTouchedUp:(PlayerView*) playerView;
-(void)playerViewDidDismiss:(PlayerView*) playerView;
#end
#interface PlayerView : UIView
+(void)presentInViewController:(UIViewController<PlayerViewDelegate>*) playerView;
-(IBAction)viewTouchedUp;
-(IBAction)dismiss;
#end
PlayerView.m (.m for reusable view)
#import "PlayerView.h"
#interface PlayerViewOwner : NSObject
#property(nonatomic,weak) IBOutlet PlayerView *playerView;
#end
#implementation PlayerViewOwner
#end
#interface PlayerView ()
#property (nonatomic, weak) UIViewController <PlayerViewDelegate> *delegateViewController;
#end
#implementation PlayerView
+(void)presentInViewController:(UIViewController<PlayerViewDelegate> *)viewController
{
PlayerViewOwner *owner = [PlayerViewOwner new];
[[NSBundle mainBundle] loadNibNamed:NSStringFromClass(self) owner:owner options:nil];
owner.playerView.delegateViewController = viewController;
[viewController.view addSubview:owner.playerView];
}
-(IBAction)viewTouchedUp
{
//forward to delegate
NSLog(#"you clicked a button");
[self.delegateViewController playerViewTouchedUp:self];
}
-(IBAction)dismiss
{
[self removeFromSuperview];
// Forward to delegate
[self.delegateViewController playerViewDidDismiss:self];
}
#end
PlayerView.xib has a UIbutton on it that connects it to viewTouchedUp method in PLayerView.m
Is there anything I did wrong in the code above? Is this the best way to do a reusable view to display on other views?
Thank you!
Here's a workaround I found after not being able to solve this.
New implementation is from this article
I reverted my changes from my initial question and implemented this. It lacks the nice protocol separation for talking back and forth and I might need something like this later but I think now I can still implement a protocol to solve this.
At least with this solution I have usable items in my view and a background that changes!

can't see properties of viewcontoller

I want to change the value of a label in my default view controller from a different class.
So I start a simple 'Single View Application' iOS project (Xcode5)
This automatically generates a ViewController for me (which I
understand is the root view controller)
I now add a label in my View and connect it to the ViewController (via IBOutlet mechanism)
I call this outlet 'gameStateLabel', so it looks like this in the ViewController.h file
#property (weak, nonatomic) IBOutlet UILabel *gameStateLabel;
Next, I have a completely separate class which has the logic for my code, and based on a condition in the logic I want to change the UIlabel.
So I try to do this from my other class:
Get an instance of the root view controller like this:
UIViewController * uvc = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
I think I now have an instance of the rootviewcontroller in uvc and should be able to reach in and change gameStateLabel.
BUT: I CANNOT do this uvc.gameStateLabel simply does not show up as a property even though it is clearly declared as a property and I've added the #synthesize for it also.
Any help will be greatly appreciated - I've been going nuts over this.
(For ref. I'm used to doing something similar on the Mac side where I'd declare a label as a property of the AppDelegate, get the instance of the Appdelegate and simply refer to the label property and change its text]
Here's the ViewController. Note that gameStateLable is a property
#import "ViewController.h"
#interface ViewController ()
#property (weak, nonatomic) IBOutlet UILabel *gameStateLabel;
#end
#implementation ViewController
#synthesize gameStateLabel;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
And here is my class cls1 (which inherits from NSObject)
#import "cls1.h"
#import "ViewController.h"
#implementation cls1
-(void) dummy{
UIViewController * uvc = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
// uvc does NOT show gameStateLabel in intellisense, i.e. uvc.gameStateLabel does NOT work
}
Add #import "mainRootVC.h" in you CustomClass.m file
And create object of mainRootVC such like,
mainRootVC *obj = [[mainRootVC alloc] init];
// Now you can access your label by
obj.gameStateLabel...
Do like this...
YourViewController *rootController =[(YourViewController*)[(YourAppDelegate*)
[[UIApplication sharedApplication]delegate] window] rootViewController];
Try the following too:
ViewController *controller = (ViewController*)self.window.rootViewController;
It will return the initial view controller of the main storyboard.
For sending information from a viewController to other viewController you have:
Delegates:Definiton and examples
NSNotificationCenter: Apple Documentation
NSString *label = #"label text";
[[NSNotificationCenter defaultCenter] postNotificationName:NAVIGATETO object:label userInfo:nil];
You can found tons of examples about those two. I recommend you use one of those.
Hope this helps a bit.
OK. I found two issues.
I had copied the code over from my Mac project and modified it. Something seems to have gone wrong.
I retyped the entire function and it solved most of the problem
uvc should be of the type ViewController* - not UIViewController* as I was doing
Thanks everyone for your replies - much appreciated.

How load a different page inside WebView when Remote Notification is received?

This a issue that have took me down since I am not able to solve it although it seems so easy.
The fact is that I have an iOS app, mainly a webview that loads a website, and I need to load different wen page when notification is received. I am implementing push notification and I have managed to get them working. They are received by the app in the App Delegate and then is when the problem starts. I would like to launch the webview with a specific URL but I don't know how to do it. I have tried to get the webview instance and passes the URL to it:
"SomeAppDelegate.h"
#import <UIKit/UIKit.h>
#class BrowserViewController;
#interface SomeAppDelegate : UIResponder <UIApplicationDelegate>
#property(nonatomic, retain) IBOutlet BrowserViewController *viewController;
#property (strong, nonatomic) UIWindow *window;
#end
"SomeAppDelegate.m"
#import "SomeAppDelegate.h"
#import "BrowserViewController.h"
#implementation SomeAppDelegate
#synthesize window = _window;
#synthesize viewController;
.........
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
[viewController.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.google.com"] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:20]];
[self.window addSubview:viewController.webView];
[self.window makeKeyAndVisible];
Another test was to create an instance method within BrowserViewContrller trying to reload from there. I also tried to load story board programatically but when "Is Initial View Controller" is unchecked in storyboard the app crashes just before launch.
I did a lot of googling but I don't understand pretty much how this life cycle works. I will thank any help.
Probably, you should set your viewcontroller as AppDelegate's window.rootViewController in the didFinishLaunching:withOptions: method of your app delegate instead of adding it's webView as window subview - because webView is only loaded after UIViewController's method viewDidLoad got called - that means that your webView might not be loaded when you're trying to reload it with request.

iOS ViewControllers

ok, this may be a very basic question and I apologise if it is, but its driving me mad and I really need to get a better understanding.
I have an app that I am developing and using a new view controller and xib file for each page.
I call each page by using this code:-
HelpVC = [[[HelpViewController alloc] initWithNibName:#"HelpViewController" bundle: [NSBundle mainBundle]]autorelease];
[self presentModalViewController:HelpVC animated:YES];
Which works great.
However if I have this declared in a file and I then want to call it somewhere else I am getting errors all over the place.
is there any way to initialise all the xib files first in a class file and then call them from that file when needed??
Thanks
This is the error I get back
error: expected specifier-qualifier-list before 'UserInputViewController'
It seems to cause all of my declarations in the .h file to error with the message above.
Some sample code is:-
.h file
#import <UIKit/UIKit.h>
#import "CgePWViewController.h"
#import "LogBackInViewController.h"
#import "LoginViewController.h"
#interface SettingsViewController : UIViewController
{
CgePWViewController *cPWVC;
LogBackInViewController *LBIVC;
LoginViewController *login;
}
#property(nonatomic, retain) CgePWViewController *cPWVC;
#property(nonatomic, retain) LogBackInViewController *LBIVC;
#property(nonatomic, retain) LoginViewController *login;
so basically as soon as I have added in LoginViewController it causes everything else to error, if I take this out then the app runs perfectly.
Does your LoginViewController.h imports the SettingsViewController as well? It seems to be a "cross reference" (I don't know if this term makes sense in English as it does in Portuguese).
Before your
#interface SettingsViewController : UIViewController
put a
#class LoginViewController;
and check if it helps.
Don't initialise your view controllers to put them in properties. Instead, create them as soon as you need them.
Let's assume you want to show a view controller when somebody pushes a button. Add this method to your view controller (let's assume it's named MyFirstViewController):
- (IBAction)someButtonDidPush: (UIButton *)sender {
MySecondViewController *vc = [[MySecondViewController alloc] init];
// Do stuff and then show it. One way may be like this:
[self presentViewController: vc animated: YES completion: nil];
}
Just hook up the button with the method above. No properties needed! You're (probably) done.

Why is my IBOutlet being released under ARC?

The Problem
An IBOutlet is released before I have a chance to use it.
What I Want
I want to access a navigation controller from my app delegate so I can reload a table view.
My Setup
I have:
A Main.xib that's set as my main interface in target settings
An IBOutlet to the navigation controller as an ivar on my app delegate
This IBOutlet hooked up to the correct navigation controller in Main.xib
App Delegate is instantiated in the xib but not set as File's Owner
I'm using ARC, Xcode 4.3.2 and iOS5.1
What I've Tried
Changing deployment target
Putting a break point on dealloc for the navigation controller, app delegate - they're never called
Reading everything I can find on ARC and IBOutlets - nothing seems to contradict what I'm doing
Creating a fresh project with just a the minimum classes required - I see exactly the same problem
Code
KPAppDelegate.h
#interface KPAppDelegate : UIResponder <UIApplicationDelegate> {
IBOutlet KPBrowseExpensesNavigationController *nc;
}
#property (strong) IBOutlet KPBrowseExpensesNavigationController *nc;
KPAppDelegate.m
#implementation KPAppDelegate
#synthesize nc;
-(void)setNc:(KPBrowseExpensesNavigationController *)nc_ {
nc = nc_; // This gets called on view load and nc gets set.
}
...snip...
// This is called about 5 seconds after app startup
-(void)objectLoader:(RKObjectLoader *)objectLoader didLoadObjects:(NSArray *)objects {
// By the time we get here, nc is nil.
UITableViewController *tvc = [[nc viewControllers] objectAtIndex:0];
[[tvc tableView] reloadData];
}
#end
UPDATE
I must be doing something really silly here. Even an incredibly simple project still shows this problem. See link below.
Download a simple test project that shows the problem.
In Window nib, set the FilesOwner Class as UIApplication and then point it's delegate from Outlets to the AppDelegate object. This is what is wrong in your project example.
is your outlet from the Interface Builder set as an KPBrowseExpensesNavigationController type?
If not it is not going to create the connection between your nib and ViewController.
You should set its Custom Class as KPBrowseExpensesNavigationController in the Identity Inspector
I am not sure why you declare it as a property & a non-property. I should do something like this:
#interface KPAppDelegate : UIResponder <UIApplicationDelegate>
#property (nonatomic, strong) IBOutlet KPBrowseExpensesNavigationController *nc;
And in your implementation:
#implementation KPAppDelegate
#synthesize nc = _nc; // So you don't accidentally use nc
...snip...
// This is called about 5 seconds after app startup
-(void)objectLoader:(RKObjectLoader *)objectLoader didLoadObjects:(NSArray *)objects {
// By the time we get here, nc is nil.
UITableViewController *tvc = [[**self.nc** viewControllers] objectAtIndex:0];
[[tvc tableView] reloadData];
}
#end
Hope this helps!
I didn't see where you alloc your nav controller. Just declaring the property won't assign any value to it, so it would be nil. In you -didFinishLaunchingWithOptions in the app delegate, set your alloc/init statement. Everything else looks fine.
KPBrowseExpensesNavigationController *nc = [[KPBrowseExpensesNavigationController alloc] init];
If you have a custom init, you can use that too, but just make sure to set it up before you try and use it.

Resources