Variable gets passed to pushed ViewController when declaring outside - ios

I have simple example:
NavViewController
ViewController
ViewController2
In ViewController:
#import "ViewController.h"
#import "ViewController2.h"
#interface ViewController ()
#end
NSArray *array;// Neither in #interface nor in #implementation
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
array = [[NSArray alloc] initWithObjects:#"12345", nil];
ViewController2 *vc = [[ViewController2 alloc] init];
[self.navigationController pushViewController:vc animated:YES];
}
In ViewConroller2:
#import "ViewController2.h"
#interface ViewController2 ()
#end
NSArray *array;
#implementation ViewController2
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"%#",array);
}
I don't understand why my array in viewController2 passed data from viewController?
Can explain this?
Guys I know how pass data to another viewController with property. I want to understand why, in this case, the data is transferred!

Because you've declared NSArray *array; as a Global variable. And, as long as the variable is defined somewhere in a source file, the linker will be able to find it and appropriately link all the references in other source files to the definition.
we also declare global variables using extern
extern int GlobalVar;
Here, externtells the compiler that this is just a declaration that an object of type int identified by GlobalVar exists and linker's job to ensure.
In one of your source file, you could say
int GlobalVar = 7;
I believe this is the reason in your case.

When you declare your variable outside #interface or #implementation it is considered to be static variable hence it worked. keep it inside would not work.
#interface ViewController ()
{
NSArray *array;
}
#end
try this instead of your code

Related

UITextFieldDelegate not working

I'm trying to separate the UITextViewDelegate methods from the main class of my project, I created a class to manage the delegate methods, but I can not change the values of the IBOulets from the main class.
I made a test project with a ViewController and a TextFieldController, in the Storyboard I add a text field and a label. What I want to do is change the text of the label when I start to write in the text field. Here is the code:
ViewController.h:
#import <UIKit/UIKit.h>
#import "TextFieldController.h"
#interface ViewController : UIViewController
#property (strong, nonatomic) IBOutlet UITextField *textField;
#property (strong, nonatomic) IBOutlet UILabel *charactersLabel;
#end
ViewController.m:
#import "ViewController.h"
#interface ViewController ()
#property (nonatomic, strong) TextFieldController *textFieldController;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
_textFieldController = [[TextFieldController alloc] init];
_textField.delegate = _textFieldController;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#end
TextFieldController.h:
#import <UIKit/UIKit.h>
#import "ViewController.h"
#interface TextFieldController : UIViewController <UITextFieldDelegate>
#end
Text Field Controller.m:
#import "TextFieldController.h"
#interface TextFieldController ()
#property ViewController *viewController;
#end
#implementation TextFieldController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (BOOL) textFieldShouldBeginEditing:(UITextField *)textField {
NSLog(#"hello");
_viewController.charactersLabel.text = #"hello";
return YES;
}
#end
When I start writing in the text field the message "Hello" is printed in the log, but the text of the label does not change. I want to know how to change the label text value from the other class.
First change the TextFieldController.h like this:
#import <UIKit/UIKit.h>
#import "ViewController.h"
#interface TextFieldController : NSObject <UITextFieldDelegate>
{
}
#property (nonatomic, assign) ViewController *viewController;
#end
Then change your TextFieldController.m file like this:
#import "TextFieldController.h"
#interface TextFieldController ()
#end
#implementation TextFieldController
- (BOOL) textFieldShouldBeginEditing:(UITextField *)textField {
NSLog(#"hello");
self.viewController.charactersLabel.text = #"hello";
return YES;
}
#end
In the ViewController.m do like that:
#import "ViewController.h"
#interface ViewController ()
#property (nonatomic, strong) TextFieldController *textFieldController;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
_textFieldController = [[TextFieldController alloc] init];
_textFieldController.viewController = self;
_textField.delegate = _textFieldController;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#end
This will work but I personally dont like that way you took.
Good luck :)
It's failing because _viewController is nil. You need to assign the viewController property in your delegate in order to support the two way communication.
Also, I'd strongly recommend you make your delegate object a subclass of NSObject, and not UIViewController. It does nothing with controlling views. You can just manually instantiate it in your ViewController objects viewDidLoad.
In TextViewController I don't see where the viewController property (_viewController ivar) is being set so it is probably nil. You should set it when you create the TextViewController instance.
When you are navigating to other controllers using storyboad's segue then you need to implement prepareForSegue method to initialised its properties as follows
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([segue.identifier isEqualToString:#"segue for textFieldController"])
{
TextFieldController *_textFieldController = [segue destinationViewController];
_textField.delegate = _textFieldController;
}
}
But I was wondering, why are you setting textFieldDelegate here, why can't you set in TextFieldController's viewDidLoad method as then you didn't you to implement above prepareForSegue method call?
Besides you are keeping strong reference of each other and you are creating strong retain cycle.
One more thing, following code
_textField.delegate = _textFieldController;
will not work, until textFieldController is loaded and its viewDidLoad method is being called as you are only initialising it but its outlets will not be connected until view is loaded into navigation stack.

How to use Protocol to passvalue between two viewcontrollers

I have two ViewControllers: A and B,
I am computing variable of B in A and then pushing B with its variable value by creating object of ViewController B. Variable of B is declare in itself. Now I am changing value of variable in ViewController B and return back to the A. I want to use Changed value of variable in A. I have tried protocol for this but in A I am getting 0 value of that variable.
Here is my code:
ViewController A.h
#import <UIKit/UIKit.h>
#import "B.h"
#class B;
#interface ViewController : UIViewController<nxtDelegate>
{
int vcheck;
}
#property(nonatomic,assign) int vcheck;
Implementation of A:
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize lbl,txt,vcheck;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
-(void)viewWillAppear:(BOOL)animated{
NSLog(#"vcheckis:%d",vcheck);
}
-(void)chngvalue:(int)i{
vcheck=i;
}
ViewController B.h
#import <UIKit/UIKit.h>
#protocol nxtDelegate <NSObject>
-(void)chngvalue:(int )i;
#end
#interface nextviewController : UIViewController<UITableViewDelegate,UIPickerViewDelegate,UIPickerViewDataSource>
{
int chcek;
}
#property(weak,nonatomic)id<nxtDelegate> delegate;
- (IBAction)btnclick:(id)sender;
#property(nonatomic,assign) int chcek;
ViewController B.m
- (IBAction)chngAction:(id)sender {
[_delegate chngvalue:chcek];
NSLog(#"%#",_delegate);}
I don't know why it's not working but I just do the below and it's work fine for me
#property(nonatomic, assign)id<nxtDelegate> Delegate;
synthesize the property name Delegate
#synthesize Delegate;
and during push I set the delegate
ViewControllerB *ViewControllerBObj=[[ViewControllerB alloc] init];
[ViewControllerBObj setDelegate:self];
[[self navigationController] pushViewController:ViewControllerBObj animated:YES];
In IBAction
- (IBAction)chngAction:(id)sender
{
if([[self Delegate] respondsToSelector:#selector(chngvalue:)])
[[self Delegate] chngvalue:chcek];
}

importing a class of functions header

I am re-factoring my code to make it more manageable I want to create a class that contains functions that I can load in to other classes.
I have created a class called functions, imported funtions.h into the .h of my ViewController Class, the functions .m to the ViewController.m but the complier does not recognise the method hasInternetconnection when is called and crashes.
I am not completely lost as to why I cannot call this method in this class
here is my code, and I have had a good look through s/o and google and I still can't see what I am doing wrong
Functions.h
#import <Foundation/Foundation.h>
#interface Functions : NSObject
-(BOOL)hasInternetConection;
#end
Functions.m
#import "Functions.h"
#implementation Functions
-(BOOL)hasInternetConection{
NSURL *url=[NSURL URLWithString:#"www.google.com"];
NSURLRequest *req=[NSMutableURLRequest requestWithURL:url];
NSHTTPURLResponse *res=nil;
[NSURLConnection sendSynchronousRequest:req returningResponse:&res error:NULL];
if (res!=nil) {
return NO;
}else{
return YES;}
}
#end
HomeViewController.h
...
#import <QuartzCore/QuartzCore.h>
#import "multiShotViewController.h"
#import "Functions.h"
...
#interface HomeViewController : UIViewController {
UIGlossyButton *b;
HomeViewController.m
...
#import "detailsViewController.h"
#import "Functions.h"
#define Kwelome #"welcomeread"
#interface HomeViewController ()
#end
#class Functions;
#implementation HomeViewController
#synthesize tripName;
#synthesize databasePath, deathtrail;
#synthesize lampingbtn,deerstalkingbtn,boundarybtn, optionsbtn,shootingbtn;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
self.navigationItem.title = #"Home";
UIColor *backg=[[UIColor alloc]initWithPatternImage:[UIImage imageNamed:#"bgcamo.png"]];
self.view.backgroundColor=backg;
[backg release];
}
return self;
}
...
I think #class Functions; is not required at least. You are importing header files already so you don't have redeclare it.
Where are you caling those methods ? Are you sure you call them on instance of that class ?
I suspect a problem that you're trying to do
[Functions hasInternetConection]
instead of
Functions * func = [[Functions alloc] init];
[func hasInternetConection];
[func release];
If you do it like in first example than change declaration to "+" instead of "-" in your function - so it can be used as static method.

setting (custom) delegate runs into infinite loop

Am trying to write a simple custom delegate for displaying multiple selection list (after referring various online tutorials, stackoverflow, Apple doc), but in the class that I want to use the delegate, the line where I set the delegate runs into an infinite loop when I run it.
I have shared the source code here
https://bitbucket.org/ikosmik/uilistviewcontroller/src/ddfcd140b52e6e59d84e58d34d601f8f850145a1/UIList?at=master
UIListViewController (where am declaring the protocols)
https://bitbucket.org/ikosmik/uilistviewcontroller/src/ddfcd140b52e6e59d84e58d34d601f8f850145a1/UIList/UIListViewController.h?at=master
And am trying to use the delegate in a UIViewController called View_Exporter
#import <UIKit/UIKit.h>
#import "UIListViewController.h"
#interface View_Exporter : UIViewController <UIListViewDelegate, UIListViewDataSource>
#property (nonatomic, strong) IBOutlet UIView *viewForList;
#property (nonatomic, strong) UIListViewController *listViewController;
#end
View_Exporter.m
#import "View_Exporter.h"
#implementation View_Exporter
#synthesize arraySelectedList;
#synthesize viewForList;
#synthesize listViewController;
#pragma mark - UIListViewController Methods
-(NSArray *) itemsForList {
NSLog(#"View_Exporter itemsForList");
NSArray *array = [NSArray arrayWithObjects:#"Server", #"Memory", nil];
return array;
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.listViewController = [[UIListViewController alloc] initWithNibName:#"UIListViewController" bundle:nil];
self.listViewController.listViewDelegate = self;
//[self.viewForList addSubview:self.listViewController.view];
self.listViewController.listViewDataSource = self;
}
#end
But this line in viewDidLoad seems to loop infinitely when I run the code :
self.listViewController.listViewDelegate = self;
Why is this looping infinitely? Am breaking my head since yesterday on this. not sure where am going wrong. can someone please help?
You've written a custom setter for listViewDelegate, at the end of this method you do this:
self.listViewDelegate = delegate;
This just calls the setter method again. Accessing a property via self. is just a way of calling[self setXX:xxx]. In your accessor method you need to set the instance variable directly, in the normal case this would be just
_delegate = delegate;
(The _delegate instance variable is created for you automatically). You can safely remove all of your synthesize statements, they aren't needed any more.

Obj-C - How to pass data between viewcontrollers using a singleton?

Alright, so this is an extension to a question I asked last night. I have a little firmer grasp on how data can be passed between view controllers using various techniques. I wanted to go the MVC route, and creating a Singleton class seems the closest concept similar to MVC.
Basically I created a simple app with two View Controllers and a singleton class. I am trying to pass the value of a text field into a UILabel. For whatever reason it isn't working. This is what my code looks like.
ViewController.h
#import <UIKit/UIKit.h>
#import "Model.h"
#import "ViewController2.h"
#interface ViewController : UIViewController {
NSString *text2pass;
}
#property (weak, nonatomic) IBOutlet UITextField *tf;
#property (weak, nonatomic) IBOutlet UILabel *btn;
- (IBAction)go:(id)sender;
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize tf = _tf;
#synthesize btn = _btn;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSString *tfstring = _tf.text;
NSLog(#"string = %#",tfstring);
}
- (void)viewDidUnload
{
[self setTf:nil];
[self setBtn:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (IBAction)go:(id)sender {
NSLog(#"btn pressed");
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
ViewController2 *vc2 = (ViewController2 *) [storyboard instantiateViewControllerWithIdentifier:#"home"];
text2pass = _tf.text;
[self passValues];
[self presentModalViewController:vc2 animated:YES];
}
-(void) passValues {
Model *model = [Model sharedModel];
model.passedText = text2pass;
}
#end
ViewController2.h
#import <UIKit/UIKit.h>
#import "ViewController.h"
#interface ViewController2 : UIViewController {
NSString *passedText;
}
#property (nonatomic)NSString *passedValue;
#property (weak, nonatomic) IBOutlet UILabel *lbl;
- (IBAction)back:(id)sender;
#end
ViewController2.m
#import "ViewController2.h"
#interface ViewController2 () {
NSString *passedtext;
}
#end
#implementation ViewController2
#synthesize lbl = _lbl;
#synthesize passedValue = _passedValue;
- (void)viewDidLoad
{
// do code stuff here
NSLog(#"passedText = %#",passedText);
_lbl.text = passedText;
[super viewDidLoad];
}
- (void)viewDidUnload
{
[self setLbl:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (IBAction)back:(id)sender {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
ViewController *vc = (ViewController *) [storyboard instantiateViewControllerWithIdentifier:#"welcome"];
[self presentModalViewController:vc animated:YES];
}
#end
Model.h
#import <Foundation/Foundation.h>
#interface Model : NSObject {
NSString *passedText;
}
#property (nonatomic, strong) NSString* passedText;
+ (Model *) sharedModel;
#end
Model.m
#import "Model.h"
#implementation Model
#synthesize passedText = _passedText;
static Model *sharedModel = nil;
+ (Model *) sharedModel {
#synchronized(self){
if (sharedModel == nil){
sharedModel = [[self alloc] init];
}
}
return sharedModel;
}
#end
The project can be downloaded in its entirety from here http://chrisrjones.com/files/KegCop-Test.zip
If you know why the UILabel is not displaying the text field text let me know. Oh I pretty much followed this -> http://www.youtube.com/watch?v=ZFGgMPcwYjg&feature=plcp
Your addressing, and memory management is just plain... off. Firstly, there's absolutely no reason to create a singleton for this, but that's beside the point here.
Secondly, when declaring properties, (atomic, assign) is defaulted to if not otherwise specified, which means your string:
#property (nonatomic)NSString *passedValue;
is weak sauce, ripe for deallocation and destruction at a moments notice. Declare it copy, strong, or retain.
Thirdly, there's absolutely no reference to your singleton in the pushed view controller, yet you seem to have the belief that objects that are named the same in different classes retain their value (especially when #import'ed). Not so. You need to reference your singleton and pull the value of [Model sharedModel].passedText into that text field.
In fact, I fixed your sample in two lines:
//ViewController2.m
#import "ViewController2.h"
//actually import the singleton for access later
#import "Model.h"
#interface ViewController2 () {
NSString *passedtext;
}
#end
#implementation ViewController2
#synthesize lbl = _lbl;
#synthesize passedValue = _passedValue;
- (void)viewDidLoad
{
// do code stuff here
NSLog(#"passedText = %#",passedText);
//actually reference the singleton this time
_lbl.text = [Model sharedModel].passedText;
[super viewDidLoad];
}
- (void)viewDidUnload
{
[self setLbl:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (IBAction)back:(id)sender {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
ViewController *vc = (ViewController *) [storyboard instantiateViewControllerWithIdentifier:#"welcome"];
[self presentModalViewController:vc animated:YES];
}
#end
Which yields this:
I wouldn't recommend using a Singleton as a good way to pass data around your application. Most apps are simple enough that this kind of central access is not necessary, and it usually creates a maintenance nightmare... but I don't think the fact that you're using a Singleton is actually important to getting your code working.
Assuming you have access to the data in ViewController1, in your case through the a Singleton instance of Model (which needs a more descriptive name), then all you have to do is pass through the data to ViewController2 when it is created and presented, which eliminates the need for a Singleton at all.
Once you create the controller, set the data you need, and then present the view controller - which is basically what you're doing anyway.
As to why it's not working: Is the view controller being presented, just not with the correct data? Or is there actually an issue presenting the controller at all? I would set a breakpoint in the go: action of ViewController1, make sure the data you expect is in the textfield, correctly populates the Model and that the value is correctly pulled out of the Model in ViewController2.
Unless you've removed some of the code, it looks like you correctly populate the Model property in ViewController1, but in ViewController2 you refer to a local ivar passedTextrather than pulling it from the model.
On a separate note, the way to go back from a presented modal view controller is usually to dismiss that controller, not to re-create the initial controller and present that over the top.

Resources