Getting null from viewController obtained from Storyboard - objective-c

I'm new to storyboards. Any ideas why this might happen?
When I fire 'test' from a button within the containing view controller the log shows vc1 (as expected)
However when I 'fire' test2 from another viewController I get null..
#property (readonly, strong, nonatomic) UIViewController *vc1;
- (IBAction)test:(id)sender {
NSLog(#"log %#", _vc1 );
}
- (void)test2 {
NSLog(#"log %#", _vc1 );
}
- (void)viewDidLoad
{
[super viewDidLoad];
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
_vc1 = [storyboard instantiateViewControllerWithIdentifier:#"test1"];
}

From your code it looks like test2 is in vc1, just do exactly as you do in vc1 in vc2

Related

How to properly initialise controls in an instantiated view controller?

I have a class ErrorMessageViewController:
// ErrorMessageViewController.h
#interface ErrorMessageViewController: UIViewController {
NSString * tempTitle;
NSString * tempContent;
}
#property (nonatomic, strong) IBOutlet UILabel* messageTitle;
#property (nonatomic, strong) IBOutlet UILabel* messageContent;
-(void) initTitle:(NSString *)title andContent:(NSString *)content;
#end
// ErrorMessageViewController.m
#implementation ErrorMessage
#synthesize messageTitle, messageContent;
-(void) initTitle:(NSString *)title andContent:(NSString *)content {
tempTitle = title == nil ? #"" : title;
tempContent = content == nil ? #"" : content;
}
- (void) viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
if (messageTitle != nil) { [messageTitle setText:tempTitle]; }
if (messageContent != nil) { [messageContent setText:tempContent]; }
}
#end
And then I put it into display using this code:
NSString * errorMessage = #"Duplicate ID";
UIStoryboard * storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
ErrorMessageViewController * errorMessage = (ErrorMessageViewController *)
[storyboard instantiateViewControllerWithIdentifier:#"ErrorMessage"];
[errorMessage initTitle:#"Error" andContent:contentVar];
[[self navigationController] pushViewController:errorMessage animated:YES];
When I debug it, on initTitle:Content:, the tempTitle and tempContent is NSCFConstString "Error" and NSCFString "Duplicate ID".
But then the flow goes to viewWillAppear, and both the tempTitle and tempContent 's contents are gone, replaced with NSCFString and NSObject. The tempTitle assignment is still OK because it's still string, though I don't know what the content is, but the tempContent assignment produce error. I can't even NSLog the tempContent value.
Why is this happened? Why the contents of the object change, like it was never initialised?
Set your data like this.
NSString * errorMessage = #"Duplicate ID";
UIStoryboard * storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
ErrorMessageViewController * errorMessage = (ErrorMessageViewController *)
[storyboard instantiateViewControllerWithIdentifier:#"ErrorMessage"];
errorMessage.messageTitle = #"Error";
errorMessage.messageContent = errorMessage;
[[self navigationController] pushViewController:errorMessage animated:YES];
and use those variable directly in your viewDidLoad or viewWillAppear.
- (void) viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
// Use your variables
}
Edit :
-(void) initTitle:(NSString *)title andContent:(NSString *)content {
tempTitle = (title == nil ? #"" : title);
tempContent = (content == nil ? #"" : content);
}
NSString * errorMessage = #"Duplicate ID";
UIStoryboard * storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
ErrorMessageViewController *vc = (ErrorMessageViewController *)
[storyboard instantiateViewControllerWithIdentifier:#"ErrorMessage"];
[vc initTitle:#"Error" andContent:errorMessage];
[[self navigationController] pushViewController:vc animated:YES];
Hope this will help
Storyboard is use lazy loading to load the subviews. messageTitle is not initialized after called instantiateViewControllerWithIdentifier. Call self.messageTitle to make the view initialized before set value.
ErrorMessageViewController * errorMessage = (ErrorMessageViewController *)
[storyboard instantiateViewControllerWithIdentifier:#"ErrorMessage"];
//tempTitle = nil
// [errorMessage initTitle:#"Error" andContent:contentVar];
[[self navigationController] pushViewController:errorMessage animated:YES];
// set value after push
[errorMessage initTitle:#"Error" andContent:contentVar];

Storing User Name in Keychain in objective c

I am new IOS to Development .I want to know about the Keychain process for storing the user name .My concept is ..if User is already logged in i need to show a password screen if not i need to show a user name screen to enter .
When i need to show the user name screen means ,in two scenarios
1)Not yet user logged in -First Time Login
2)Logged in and logout from the app by pressing logout button in password screen
This much of code only i did in app delegate ,here what i am doing is i am just storing the username in NSUserDefaults and if user name exists then i am showing second screen i.e., Password screen .
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
ViewController *controller = (ViewController *)self.window.rootViewController;
NSUserDefaults *User = [NSUserDefaults standardUserDefaults];
NSString *userid = [User stringForKey:#"userName"];
if (userid != nil)
{
self.window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
// determine the initial view controller here and instantiate it with
UIViewController *viewController = [storyboard instantiateViewControllerWithIdentifier:#"PassVC"];
self.window.rootViewController = viewController;
[self.window makeKeyAndVisible];
}
else
{
self.window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
// determine the initial view controller here and instantiate it with
UIViewController *viewController = [storyboard instantiateViewControllerWithIdentifier:#"LoginVC"];
self.window.rootViewController = viewController;
//viewController.man
[self.window makeKeyAndVisible];
}
return YES;
}
Now , What i want is ,instead of storing userid in NSUser Defaults, i want to store userid in keychain .I don't have knowledge about the keychain .i searched in google but i didn't found anything clearly .Whether i need to include any frameworks for keychain ??Please anyone help me with the example code .Thanks in Advance !!!
Thanks of the reply .. i have created the keychain .when i tried to print the keychain object it is showing nil.i don't know why?
this is my code..
This is my ViewController.h
#import <UIKit/UIKit.h>
#import "KeychainItemWrapper.h"
#interface ViewController : UIViewController {
KeychainItemWrapper *keyChain ;}
#property (weak, nonatomic) IBOutlet UIView *sub_View;
#property (weak, nonatomic) IBOutlet UITextField *UserId_txt;
#property (weak, nonatomic) IBOutlet UIButton *clickMe_btn;
- (IBAction)btn1:(id)sender;
#end
This is my View Controller .m
#import "ViewController.h"
#import "PasswordViewController.h"
#import "KeychainItemWrapper.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.UserId_txt.delegate = self;
NSString *userid = self.UserId_txt.text;
[keyChain setObject:userid forKey:#"user_id"];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
-(BOOL) textFieldShouldReturn:(UITextField *)textField{
[textField resignFirstResponder];
return YES;
}
- (IBAction)btn1:(id)sender {
NSString *user =[keyChain objectForKey:#"user_id"];
NSLog(#" the user id is :%#",user);
PasswordViewController *PassVC = [self.storyboard instantiateViewControllerWithIdentifier:#"PassVC"];
[self.navigationController pushViewController:PassVC animated:YES];
}
#end

Impossible to presentViewController

I've created a new application view based.
Here some the main code:
// AppDelegate.h
#interface AppDelegate : UIResponder <UIApplicationDelegate>
{
UINavigationController *navigationController;
MIAPreferences *preferences;
}
#property (strong, nonatomic) UINavigationController *navigationController;
#property (strong, nonatomic) UIWindow *window;
#property (strong, nonatomic) MIAPreferences *preferences;
// AppDelegate.m
#implementation AppDelegate
#synthesize window = _window;
#synthesize navigationController;
#synthesize preferences;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationFade];
// Override point for customization after application launch.
UIViewController *rootController = [[HomeViewController alloc] initWithNibName:nil bundle:nil];
navigationController = [[UINavigationController alloc]
initWithRootViewController:rootController];
navigationController.navigationBar.hidden = YES;
self.window = [[UIWindow alloc]
initWithFrame:[[UIScreen mainScreen] bounds]];
_window.rootViewController = navigationController;
[self.window makeKeyAndVisible];
return YES;
}
// HomeViewController.m
-(IBAction)openLogin
{
LoginViewController *view = [[LoginViewController alloc] initWithNibName:nil bundle:nil];
// 1
[self.navigationController presentViewController:view animated:YES completion:nil];
// 2
[self.navigationController pushViewController:view animated:YES];
// 3
[self presentViewController:view animated:YES completion:nil];
}
All 3 options returns a EXC_BAD_ACCESS (code=2, address=....)
Can you please help me understand how to solve this?
UPDATE
The problem was due to a UIButton apparence set up during AddDelegate loading....but the first button was in the UIView I was going to load... that's why it crashed -.-"
It could either mean: (1) The pointer used to point to memory that was ok, but its chunk was deallocated or (2) The pointer is corrupt. You can try to use zombie mode, if you aren't already, to get more information. In XCode press the Command, option, and I keys and a screen should pop up. Selected the Run option in the left hand side, then Diagnostics, and under memory management enable zombie objects should be checked.
Check the value of view after initWithNibName:. init'ing with a nil nib name looks wrong to me, and you may be trying to push a nil view controller onto your navigation stack.

Objective c: Protocol + Delegate to pass data back from Login form in a Modal View to an tab bar controller view

I'm developing a tab bar based app for iPhone.
The flow is the following: when the app runs, I throw up the modal view with the login form:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
tabBarController.delegate = self;
// Add the tab bar controller's view to the window and display.
self.window.rootViewController = self.tabBarController;
[self addTabBarArrow];
LoginViewController *loginViewController = [[LoginViewController alloc] init];;
[window addSubview:tabBarController.view];
[self.tabBarController presentModalViewController:loginViewController animated:YES];
[window makeKeyAndVisible];
return YES; }
In the log in modal view LoginViewController.h (child) I've got a protocol implemented:
#protocol PassUserInfoDelegate <NSObject>
#required
- (void) passUserInfo: (NSString *)string;
#end
When the user fills out the form, I create a NSURLConnection, and in the connectionDidFinishLoading method I get the user values from an JSON request:
-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSString *respuestaServidor = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
self.responseData = nil;
NSDictionary *dictionary = [respuestaServidor JSONValue];
idJson = [dictionary objectForKey:#"id"];
NSString *user_loginJson = [dictionary objectForKey:#"user_login"];
if ([idJson isEqualToString:#"null"] && [user_loginJson isEqualToString:#"null"]) {
NSLog(#"Login incorrecto");
} else {
NSLog(#"Procedo a loguear usuario");
}
[indicator stopAnimating];
[indicator release];
}
In HomeViewController.h (parent) I've got the delegation:
#interface HomeViewController : UIViewController <PassUserInfoDelegate> {
LoginViewController *protocolTest;
IBOutlet UILabel *nombreUsuario;
NSString *usuario;
}
#property (nonatomic, retain) IBOutlet UILabel *nombreUsuario;
#property (copy) NSString *usuario;
- (void) passUserInfo:(NSString *)string;
#end
and in the HomeViewController.m I implement the Protocol method:
- (void) passUserInfo:(NSString *)jSonString
{
userName.text = [[NSString alloc] initWithFormat:#"Welcome %#", jSonString];
}
and in the viewDidAppear method I call the loginSuccess method implemented in the LoginViewController class
-(void) viewDidAppear:(BOOL)animated{
protocolTest = [[LoginViewController alloc] init];
[protocolTest setDelegate:self];
[protocolTest loginSuccess];
}
loginSuccess method implemented in the LoginViewController class:
- (void)loginSuccess
{
[[self delegate] passUserInfo:idJson];
}
and it should pass the idJson value to the HomeViewController (parent).
The problem is that when I dismiss the modal view form, the idJson value is "NIL", so then in the HomeViewController I can't get this value. If I make this instead:
[[self delegate] passUserInfo:#"hello"];
I get the hello string in the HomeViewController (parent)
What am I doing wrong??
Thanks in advance!!!
Your problem is that instead of using the existing LoginViewController that has the actual data. Your viewWillAppear is creating a new one that never made the connection and getting its empty data.
First in the app delegate, you need to set your HomeViewController (the one in the tabbar) as the delegate to the LoginViewController that you're presenting.
Then, from connectionDidFinishLoading: you should be calling the [delegate passUserInfo:idJson]; to inform the HomeVC that the login screen got data.
You HomeVC's passUserInfo: method should probably dismiss the LoginVC with [self.tabBarController dismissModalViewControllerAnimated:YES]; (Since the login view was presented from the tabbar controller).

UISwitch returns NULL?

I have a UISwitch that returns (null) for some reason. Below is my code:
AddAlbumViewController:
// .h
IBOutlet UISwitch *photostreamSwitch;
#property (nonatomic, retain) IBOutlet UISwitch *photostreamSwitch;
// .m
#synthesize photostreamSwitch;
photostreamSwitch = [[UISwitch alloc] init];
NSLog(#"photostreamSwitch: %#", photostreamSwitch); // returns a not-null value
SecondViewController:
//.m
- (IBAction)createAlbum:(id)sender {
AddAlbumViewController *addAlbumViewController = [[AddAlbumViewController alloc] initWithNibName:#"AddAlbum" bundle:[NSBundle mainBundle]];
NSLog(#"Test Switch: %#",addAlbumViewController.photostreamSwitch); // returns null
[addAlbumViewController release];
}
I think I have everything set up right. If this helps, AddAlbumViewController is inside a UINavigationController and SecondViewController contains the UINavigationController.
The view controller is created but its view (i.e. its nib) is not loaded yet, therefore the property isn't connected yet. You can force the nib to load by accessing the view member of the controller:
- (IBAction)createAlbum:(id)sender {
AddAlbumViewController *addAlbumViewController = [[AddAlbumViewController alloc] initWithNibName:#"AddAlbum" bundle:[NSBundle mainBundle]];
UIView* tempView = addAlbumViewController.view;
NSLog(#"Test Switch: %#",addAlbumViewController.photostreamSwitch); // no longer null
[addAlbumViewController release];
}