Changing UI from AppDelegate - ios

I try to set a UITextView from my AppDelegate, when the application did finished launching.
Actually I just want to open a file and pass it's contents to a UITextView.
In my ViewController I added the following method:
ViewController.h:
#interface
{
IBOutlet UITextView *textView;
}
- (void)openFile:(NSString *)myString;
ViewController.m:
- (void)openFile:(NSString *)myString
{
textView.text = myString;
}
In my AppDelegate the following:
AppDelegate.m:
#import "ViewController.h"
#implementation AppDelegate
- (BOOL)application: [...] didFinishLaunchingWithOptions: [...]
{
ViewController *test = [[ViewController alloc] init];
[test openFile:#"this is a test"];
}
When I attempt call the method from my AppDelegate, it actually gets called and passes the string as expected.
I tested via NSLog(#"%#", myString);.
But the value of textView doesn't change.
First I thought there could be an other problem, so I called the method with a UIButton after loading the view etc. But it was everything okay and the textView changed.
Then I thought, the view might be loaded after I calling my method from the AppDelegate.
I put in a few NSLogs more and it turned out, that the view is fully loaded, then my AppDelegate calls the method.
So the AppDelegate calls [test openFile:(NSString *)] after the view is fully loaded and it's passing the String. But the value of my textView is still not changing.
Any suggestions on this?
Did anybody of you run into the same problem?

You are not loading any view for ViewController. So the outlet is connected to nothing. if you are loading views and ViewController from NIB (xib) file, then you don't have to create another instance of ViewController. That is what you are doing when alloc and init a new ViewController, create a new instance connecting to nothing.
As there is a IBOutlet I suppose there is a xib file. Try something like
- (BOOL)application: [...] didFinishLaunchingWithOptions: [...]
{
ViewController *test = [[ViewController alloc] initWithNibName:#"YourXibName"
boundle:nil ];
[test openFile:#"this is a test"];
self.window.rootViewController = test.view ;
[self.window makeKeyAndVisible];
return YES;
}

Wasn't exactly what I needed. But you gave me the right idea.
Thanks a lot!
self.viewController = [[test3ViewController alloc] initWithNibName:#"YourXibName" bundle:nil];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
[self.viewController openFile:#"Der Test"];

Related

How do I start another view controller with no storyboard?

I'm not using a storyboard or anything. I'm just creating the cocoa classes and linking them up individually. I can get to load up the default View Controller which is SplashViewController but i can't get past there.
I have experience in php, android programming and python, but i'm totally clueless on how Obj-C and how the iOS framework works :(
SplashViewController.m
-(void)initializeInterface
{
//Initialize start button
[self.startButton addTarget:self action:#selector(startActivity) forControlEvents:UIControlEventTouchDown];
//Initialize fading backgrounds
[self animateImages];
}
-(void)startActivity
{
PhoneViewController *phoneView = [[PhoneViewController alloc] initWithNibName:#"PhoneViewController" bundle:nil];
[self.navigationController pushViewController:phoneView animated:YES];
}
SplashViewController.h
#import <UIKit/UIKit.h>
#import "PhoneViewController.m"
#class PhoneViewController;
#interface SplashViewController : UIViewController
#property (strong, nonatomic) PhoneViewController * phoneViewController;
#property UIImage *splashbg1;
#property UIImage *splashbg2;
#property (nonatomic, retain) IBOutlet UIImageView *splashbg;
#property (nonatomic, retain) IBOutlet UIButton *startButton;
-(void)initializeInterface;
-(void)animateImages;
-(void)startActivity;
#end
EDIT
classAppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor];
//Move from delegate view controller to root view controller
self.window.rootViewController=[SplashViewController new];
[self.window makeKeyAndVisible];
return YES;
}
Wrap your splash view controller in a navigation controller.
Otherwise, the navigationController property of your splash view controller is nil and pushViewController has no effect.
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController: splashViewController];
To move from one UIViewController to other UIViewController, you can try the following things
If SecondViewController *secondViewController is the UIViewController you want to move in to, then your can do the following:
[self presentViewController: secondViewController animated:YES completion:nil];
This is when you UIViewController is not embedded inside a UINavigationController.
It is possible to create your view controllers entirely in code without using Storyboards or XIB files, but it's not recommended. It's like trying to write a complex user application in assembler. The state of the art has evolved since the days when that was necessary. There are better tools. Use them.
Creating everything yourself is both quite complex and not very well documented. You are setting yourself up for a very frustrating, error-prone process. I've been doing iOS development pretty much full time since 2009, and I would not attempt this.
That being said, if you are a masochist, you would create your view controller using initWithNibName:bundle:, passing in nil for both parameters, and then implement the loadView method. In loadView you're create your view hierarchy and install it.
If you are new to iOS/Objective-C, DO NOT DO THIS. It is like trying to write a kernel device driver in machine code as your first foray into UNIX.
Change you AppDelegate method as below -
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor];
UINavigationController *navcon = [[UINavigationController alloc]initWithRootViewController:[SplashViewController new]];
//Move from delegate view controller to root view controller
self.window.rootViewController=navcon;
[self.window makeKeyAndVisible];
return YES;
}
Problem in your code, you have not taken any navigationController, that enables you push or pop UIViewController. Doing above you can use your method -(void)startActivity to Start a new ViewController.

Memory management ARC and view controllers

I was thinking about this today, and now i've tested i'm a little confused…
When using viewControllers either by pushing a viewController onto the Navigation Stack or Presenting a ViewController modally I'm wondering about memory management.
Lets use the modal example as a thought experiment, here is the source to create and present the view, in my example it doesn't matter if ARC or not so here's both:
With ARC:
ViewController *myViewController = [[ViewController alloc] init];
myViewController.delegate = self;
[self presentViewController:myViewController animated:YES completion:NULL];
Without ARC:
ViewController *myViewController = [[ViewController alloc] init];
myViewController.delegate = self;
[self presentViewController:myViewController animated:YES completion:NULL];
[myViewController release]; //As it's now 'owned' by the presenting View controller
This would be my understanding about how to present a viewController modally over an existing ViewController.
Lets say for our example the above code resides in a method which is called when a button is touched to present the ViewController.
Now to my question,
What I am doing is calling this code each time a button is touched, During testing with Instruments I didn't seem to have any leaks. - However because I have NSLog statements in the myViewController dealloc & viewDidLoad methods I know that it's getting instanciated everytime I touch the button but never deallocated.
So...
A) Why am I not getting a leak showing (or a rise in Live Bytes) in instruments (when either using ARC or not) because I am seemingly creating a new viewController and leaking the old one each time I go to present it.
B) What is the correct way to write the above code if this is not memory safe? I see this kind of code snippets all over Apple's example code and internet. Should I (and they) not be wrapping the alloc init line in an if statement to check if the object is already created?
i.e.
if(!myViewController)
{
ViewController *myViewController = [[ViewController alloc] init];
}
myViewController.delegate = self;
[self presentViewController:myViewController animated:YES completion:NULL];
Thanks for taking the time to read and answer, I really wonder about this as I've been creating, pushing and presenting ViewControllers using the above code the whole time, and never noticed a leak! - might have to go back and rewrite it all!
To avoid confusion please note: The delegate property is a custom property of my UIViewController subclass (where I've implemented a delegate protocol), required to dismiss the Modally present Viewcontroller properly. As per coding guidelines.
Regards,
John
EDIT As Requested, Creation of the delegate:
.h
#protocol NotificationManagementViewControllerDelegate;
#interface NotificationManagementController :
{
__weak NSObject <NotificationManagementViewControllerDelegate> *delegate;
}
#property (nonatomic, weak) NSObject <NotificationManagementViewControllerDelegate> *delegate;
#protocol NotificationManagementViewControllerDelegate <NSObject>
#optional
- (void)didFinishSettingNotification:(NotificationManagementController *)notificationManagementController;
.m
- (void)sendMessageToDismiss {
if ([[self delegate] respondsToSelector:#selector(didFinishSettingNotification:)]) {
[self.delegate didFinishSettingNotification:self];
}
}
And finally in the delegates .m:
- (void)didFinishSettingNotification:(NotificationManagementController *)notificationManagementController
{
[self dismissViewControllerAnimated:YES completion:NULL];
}
You are not getting a leak because you create a new controller and ARC will release this allocation for you.
But, it's better to create a #property for your new view controller.
and modify your i.e. implementation like :
#property (nonatomic, strong) ViewController *myViewController;
if (!_myViewController)
self.myViewController = [[ViewController alloc] init];
self.myViewController.delegate = self;
[self presentViewController:_myViewController animated:YES completion:nil];
Here, you have a lazy property and you don't create a new one ViewController after the first creation.
But, you need to pass your delegate (or any property) outside your test.
Furthermore, if you use your first implementation and add this controller in a subview of the current controller without property, this will work but you will get a leak.
I got this experience with the code below :
RootViewController
- (void)viewDidLoad
{
[super viewDidLoad];
ViewController *myViewController = [[ViewController alloc] init];
[self.view addSubview:myViewController.view];
}
myViewController will be add on the screen but released immediately without keeping any reference of the object, so if you add an action in 'ViewController`, your application will crash without explanation of XCode.
So, the correct way to write this without leak will be :
- (void)viewDidLoad
{
[super viewDidLoad];
if (!_myViewController)
self.myViewController = [[ViewController alloc] init];
[self.view addSubview:self.myViewController.view];
}
The answer is a bit longer and can be improved so don't hesitate !
Hope it's going to help some people.

viewDidLoad is not called for rootViewController

This is my first iOS project. I'm just following the tutorial from Try iOS over at codeschool in my XCode Application.
I've added a button in my viewDidLoad method. I don't think this is where it would be added normally, but it should still work. The problem is, the method is never called. Here's my code so far:
AppDelegate.m:
#import "AppDelegate.h"
#import "ViewController.h"
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//Set window size & background color
CGRect viewRect = [[UIScreen mainScreen] bounds];
self.window = [[UIWindow alloc] initWithFrame:viewRect];
self.viewController = [[ViewController alloc] init];
UIView *view = [[UIView alloc] initWithFrame:viewRect];
view.backgroundColor = [UIColor yellowColor];
self.viewController.view = view;
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
NSLog(#"Screen is %f tall and %f wide", viewRect.size.height, viewRect.size.width);
return YES;
}...
AppDelegate.h:
#import <UIKit/UIKit.h>
#class ViewController;
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (strong, nonatomic) ViewController *viewController;
#end
ViewController.m:
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor blueColor];
UIButton *firstButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
firstButton.frame = CGRectMake(100, 100, 100, 44);
[firstButton setTitle:#"Don't Click!" forState:UIControlStateNormal];
[self.view addSubview:firstButton];
}...
When the app is up and running, my background remains yellow, and there is no button visible.
Stepping through the application, didFinishLaunchingWithOptions: hits as I expected. When the view is initializes, I expect the viewDidLoad to run. I may just be misunderstanding the way C "sends messages".
If any additional information might help please let me know. Thanks for any help :)
EDIT
Does this have something to do with storyboarding? I'm in storyboard mode but I never added any button using the GUI
viewDidLoad is not being called because of the non-standard way that you're creating its view. Usually, the view is loaded from a xib or storyboard, or created in code in the loadView method of the view controller -- in all these cases, viewDidLoad will be called. If you move your view creation to loadView in the controller's .m file, it will work, and viewDidLoad will be called.
After Edit:
If you're using a storyboard, your view should be created there, and you shouldn't be doing what you're doing in the app delegate. In fact, when you use a storyboard, you don't normally have any code in the application:didFinishLaunchingWithOptions: method.
...
self.viewController.view = view;
...
You shouldn't set viewController's view before viewDidLoad, which cause viewDidLoad not called. View should be set in viewDidLoad, and the viewController's will manage its view automatically for you.
Looking at the code, this is exactly what should be happening. When you create a viewController, it automatically creates a view so you do not want to create a new one for it. Your button is not showing up because it is on the original view created with the viewController but you overwrote it with your yellow view.
Instead what you want to do is go into ViewController.m's viewDidLoad:(BOOL)animated and add:
[self.view setBackgroundColor:[UIColor yellowColor]];
Also, make sure that you do not set viewController.view in appDelegate. If you do not set that, a view is automatically created and you can add your button or any other views to it in the viewDidLoad.
I had this issue, and the initWithCoder function was called when I added some code in the AppDelegate's didFinishLaunchingWithOptions function.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];(NSDictionary *)launchOptions
UIStoryboard* storyboard = [UIStoryboard storyboardWithName:#"MyStoryboardName" bundle:nil];
UIViewController *initViewController = [storyboard instantiateInitialViewController];
[self.window setRootViewController:initViewController];

JASlidingpanels storyboard example root view controller error

I am trying to implement the JASliding panels by using story boards i have created a left and center panel as well as a subclass for the jaslider class
#import "RootViewController.h"
#interface RootViewController ()
#end
#implementation RootViewController
-(void) awakeFromNib
{
[self setLeftPanel:[self.storyboard
instantiateViewControllerWithIdentifier:#"leftViewController"]];
[self setCenterPanel:[self.storyboard
instantiateViewControllerWithIdentifier:#"centerViewController"]];
[self setRightPanel:nil];
}
#end
i only want to use the left and center panels.
i keep getting this in the output
JASidePanelSB[31404:c07] Application windows are expected to have a root view controller at the end of application launch
I have created the viewers in the storyboard with the identifiers and the viewer ascociated with the RootViewController is the initial view with the arrow on the left side.
is there something else that i am missing
I think your problem lie in the method. You are calling awakeFromNib but are using storyboards. Try putting your code in like this:
#import "RootViewController.h"
#interface RootViewController ()
#end
#implementation RootViewController
-(void)viewDidLoad
{
[self setLeftPanel:[self.storyboard
instantiateViewControllerWithIdentifier:#"leftViewController"]];
[self setCenterPanel:[self.storyboard
instantiateViewControllerWithIdentifier:#"centerViewController"]];
[self setRightPanel:nil];
[self.sidePanelController showCenterPanelAnimated:YES];
[super viewDidLoad];
}
#end
Notice that I am using viewDidLoad and not awakeFromNib because awakeFromNib is called when the controller itself is unarchived from a nib. viewDidLoad is called when the view is created/unarchived.
You don't got no nibs.
Ok so I figured it out. Since I started the project as an empty application, XCode added the code to alloc a new UIWindow object that was interfering and giving the error. If anyone else wonders, make sure this code isn't in the didFinishLoadingWithOptions method
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];

ViewController programmatically?

I would like to know what steps are needed once a fresh "Single view" project was created in xcode, in order to achieve:
1. a viewController that initializes without a NIB, but rather programmatically loads it's own controls in its view.
2. How to get that viewcontroller's view to load and call viewDidLoad?
3. make the view for that controller visible on the screen with all of the controls.
How do I go about this from this function:
-(BOOL)application:(UIApplication*)application didFinishLoadingWithOptions:(NSDictionary *)launchOptions
I am trying to modify a new xcode project but all I get is a black screeen, viewDidLoad doesn't get called
That's your app delegate's application loading method.
In there, you would probably want to create an instance of your custom view controller and assign that as the rootViewController to your app delegate didFinishLoading. There should be a line like:
// app delegate .h file
#import "CustomViewController.h"
#interface
{
...
CustomViewController *myCustomVC;
...
}
#property (nonatomic, retain) CustomViewController *myCustomVC;
// app delegate .m file
#implementation AppDelegate
#synthesize myCustomVC;
-(BOOL)application:(UIApplication*)application didFinishLoadingWithOptions:(NSDictionary *)launchOptions
{
...
myCustomerVC = [[CustomViewController alloc] init];
[self.window setRootViewController:myCustomVC];
...
}
Then inside your custom view controller's viewDidLoad method, you can do this as a test:
// custom view controller .m file
-(void)viewDidLoad
{
self.view.backgroundColor = [UIColor redColor];
}
UIViewController *myViewController = [[UIViewController alloc] init];
[myViewController.view setFrame:self.view.bounds];
[self.view addSubview:myViewController.view]; // if you want to add it in another viewcontroller
// For testing, set the background color to something other than white (default)
[myViewController.view setBackgroundColor:[UIColor greenColor]];
And off you go !
You need to create a subclass of UIViewController, and setup your view hierarchy either in loadView, or viewDidLoad (depending on the level of customisation)
By subclassing UIViewController the loading method calls will be made for you so you don't have to worry about getting getting viewDidLoad etc.
To make it visible on the screen the simplest way is to set it as the rootViewController of the apps window
inside didFinishLaunchingWithOptions: in your app delegate
self.window.rootViewController = [[MyViewControllerSubclass alloc] init];
Try This :
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
HomeViewController *homeVC = [[HomeViewController alloc]init];
[self.window setRootViewController:homeVC];
[self.window makeKeyAndVisible];
return YES;
}
Remove Main(storyboard reference) from Main interface of general Setting :
Add Launch Image :
And select iOS-7 and later in your left corner setting

Resources