iOS - Passing variable to view controller - iphone

I have a view with a view controller and when I show this view on screen, I want to be able to pass variables to it from the calling class, so that I can set the values of labels etc.
First, I just tried creating a property for one of the labels, and calling that from the calling class. For example:
SetTeamsViewController *vc = [[SetTeamsViewController alloc] init];
vc.myLabel.text = self.teamCount;
[self presentModalViewController:vc animated:YES];
[vc release];
However, this didn't work. So I tried creating a convenience initializer.
SetTeamsViewController *vc = [[SetTeamsViewController alloc] initWithTeamCount:self.teamCount];
And then in the SetTeamsViewController I had
- (id)initWithTeamCount:(int)teamCount {
self = [super initWithNibName:nil bundle:nil];
if (self) {
// Custom initialization
self.teamCountLabel.text = [NSString stringWithFormat:#"%d",teamCount];
}
return self;
}
However, this didn't work either. It's just loading whatever value I've given the label in the nib file. I've littered the code with NSLog()s and it is passing the correct variable values around, it's just not setting the label.
Any help would be greatly appreciated.
EDIT: I've just tried setting an instance variable in my designated initializer, and then setting the label in viewDidLoad and that works! Is this the best way to do this?
Also, when dismissing this modal view controller, I update the text of a button in the view of the calling ViewController too. However, if I press this button again (to show the modal view again) whilst the other view is animating on screen, the button temporarily has it's original value again (from the nib). Does anyone know why this is?

When a view controller is being initialized, inside the initWithNibName method, the views that reside in the view controller aren't yet initialized and you can't set their properties yet. Do whatever you need that is view based in the "viewDidLoad" method.

I am not a pro but this may help you.
In the header view1.h, declare the desired property:
// view1.h
#interface view1 : UIViewController {
NSString *passingVariable;
}
#property (nonatomic, strong) NSString *passingVariable;
#end
and then in the implementation of view1, synthesize the variable:
// view1.m
#implementation view1
#synthesize passingVariable;
// the rest of the implementation
#end
and, finally in the implementation of the other view controller, view2:
// view2.m
#import "view1.h"
#implementation view2
-(IBAction)changeview
{
view1 *myview = [[view1 alloc] init];
myview.passingVariable = #"Hello Variable";
[self.navigationController pushViewController:myview animated:YES];
}
#end
here i am trying to move from view2 to view 1 and also initializing the passingVariable ivar of view1. hope this will help you.

Here i'm passing the ViewController's label text to SecondViewController's Label Text
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
{
// please make your control on XIB set these IBOutlet's
//I'm not showing how to connect these with XIB
IBOutlet UILabel *lblView;
IBOutlet UIButton *buttonGo;
}
//this is method which will push the view
-(IBAction)buttonGoClickAction:(id)sender;
ViewController.m
-(IBAction)buttonGoClickAction:(id)sender
{
SecondViewController *secondViewObject = [[SecondViewController alloc]initWithNibName:#"SecondViewController" bundle:nil];
//before pushing give the text
secondViewObject.string = lblView.text;
[self.navigationController pushViewController:secondViewObject animated:YES];
}
SecondViewController.h
#import <UIKit/UIKit.h>
#interface SecondViewController : UIViewController
{
IBOutlet UILabel *labelView;
NSString *string;
}
//set the string property
#property(nonatomic, retain) NSString *string;
#end
SecondViewController.m
#import "SecondViewController.h"
#implementation SecondViewController
//synthesize string here
#synthesize string;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
//Here you will get the string
labelView.text = string;
}

Firstly you check that have you attach this label IBOutlet in xib or not if you made it via Interface Builder....
use it like this....
SetTeamsViewController *vc = [[SetTeamsViewController alloc] initWithTeamCount:teamCount];
Take a string variable in .h file and set that string here .. NSSting *str in .h
- (id)initWithTeamCount:(int)teamCount {
self = [super init];
if (self) {
// Custom initialization
str = [NSString stringWithFormat:#"%d",teamCount];
}
return self;
}
and set your label in viewDidLoad: or in viewWillApear:
self.teamCountLabel.text = str;
May this will help you

As said by stavash, control in the xib are created in the view did load. To be more precise, they are created with that line :
[super viewDidLoad];
So, mylabel doesn't exist before that time (it is nil).
The easiest way is to do that :
SetTeamsViewController *vc = [[SetTeamsViewController alloc] init];
[self presentModalViewController:vc animated:YES];
vc.myLabel.text = self.teamCount;
[vc release];
The longer but more correct path is to have a member NSString* in SetTeamsViewController class, to set it to teamCount before showing the window, and in the view did load to put that membre value in your label.
Cdt

It depends on your need. You can use Singleton class for sharing of your variables between different classes. Define all variable which you wants share in your DataClass.
in .h file (where RootViewController is my DataClass, replace name with your new class)
+(RootViewController*)sharedFirstViewController;
in .m file
//make the class singleton:-
+(RootViewController*)sharedFirstViewController
{
#synchronized([RootViewController class])
{
if (!_sharedFirstViewController)
[[self alloc] init];
return _sharedFirstViewController;
}
return nil;
}
+(id)alloc
{
#synchronized([RootViewController class])
{
NSAssert(_sharedFirstViewController == nil,
#"Attempted to allocate a second instance of a singleton.");
_sharedFirstViewController = [super alloc];
return _sharedFirstViewController;
}
return nil;
}
-(id)init {
self = [super init];
if (self != nil) {
// initialize stuff here
}
return self;
}
after that you can use your variable in any other class like this
[RootViewController sharedFirstViewController].variable
Hope it's help you:)

With Storyboards the the right way is to pass the indexPath as sender argument in performSegueWithIdentifier
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self performSegueWithIdentifier:#"segueIdentifier" sender:indexPath];
}
and to set a property in the destination controller:
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString: #"segueIdentifier"]) {
NSIndexPath *indexPath = sender;
DetailViewController *dest = [segue destinationViewController];
dest.usersArray = [self.usersArray objectAtIndex:indexPath.row];
}
}

What I have done whenever I needed another class to have the variables from the previous class I either set up a global class that will store the values incase I need them in more locations or in the interface you can set #public variables. These variables can be set using the controller that you created for the next view as such.
controller->pub_var1 = val1;
controller->pub_var2 = val2;
This will be done before you pass the view to the root controller or just before you call the next view. You will need to #import "class.h" so that you can access those public variables.
I can show code if this is not clear

Related

How to change MutableArray from other view?

In my Application,
There are two different views ItemList And ItemSearch.
In ItemList file I have one NsMutableArray with name tblItem. I want pass data in tblitem from the Itemsearch page.
How can I do this?
You can make use of properties as follows:
1.Create a property in ItemList.h of tblItem as,
#property(nonatomic, retain) NSMutableArray *tblItem;
then synthesize it in ItemList.m,
#synthesize tblItem;
When you are navigating from ItemSearch to ItemList ie when you are initializing ItemList just provide tblItem the required values as,
ItemListObj.tblItem = theSearchedArray;
Declare an NSMutableArray as property in the SecondViewController and assign the array at the time you are pushing or presenting the SecondViewController from the FirstViewController.
#interface SecondViewController : UIViewController
{
NSMutableArray *aryFromFirstViewController;
}
#property (nonatomic,retain) NSMutableArray *aryFromFirstViewController;
#end
At the implementation, synthesize the property
#implementation SecondViewController
#synthesize aryFromFirstViewController;
#end
At the header of the FirstViewController import the SecondViewController
#import "SecondViewController.h"
At implementation of the FirstViewController, add the code like below in where you wrote the code to present or push the SecondViewController
#implementation FirstViewController
- (void) functionForPushingTheSecondViewController
{
SecondViewController *objSecondViewController = [[SecondViewController alloc] initWithNIBName: #"SecondViewController" bundle: nil];
objSecondViewController.aryFromFirstViewController = self.myAryToPass;
[self.navigationController pushViewController:objSecondViewController animated: YES];
[objSecondViewController release];
}
#end
Please don't forget to release the aryFromFirstViewController at dealloc method of SecondViewController, otherwise it will leak because we retained it. I'l feel good if i come to know that this helped you in someways. Enjoy.
It depends on your need. You can use Singleton class for sharing of your variables between different classes. Define all variable which you wants share in your DataClass.
in .h file (where RootViewController is my DataClass, replace name with your new class)
+(RootViewController*)sharedFirstViewController;
in .m file
//make the class singleton:-
+(RootViewController*)sharedFirstViewController
{
#synchronized([RootViewController class])
{
if (!_sharedFirstViewController)
[[self alloc] init];
return _sharedFirstViewController;
}
return nil;
}
+(id)alloc
{
#synchronized([RootViewController class])
{
NSAssert(_sharedFirstViewController == nil,
#"Attempted to allocate a second instance of a singleton.");
_sharedFirstViewController = [super alloc];
return _sharedFirstViewController;
}
return nil;
}
-(id)init {
self = [super init];
if (self != nil) {
// initialize stuff here
}
return self;
}
after that you can use your variable in any other class like this
[RootViewController sharedFirstViewController].variable
Hope it's help you:)

Why is my delegate method not called?

this is probably simple but I'm stuck!
Basically I have a parent and child view controller, and I'm trying to pass data from the child to the parent.
//Child VC interface
#protocol ANSearchGetawayFilterDelegate
-(void)selectedCell:(NSString *)cellTitle;
#end
#interface ANSearchGetawayFilterViewController : UIViewController <UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate>
{
NSString* cellTitle;
}
#property (nonatomic, assign) id<ANSearchGetawayFilterDelegate> delegate;
#end
//Child VC implementation
#implementation ANSearchGetawayFilterViewController
#synthesize delegate = _delegate;
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
cellTitle = selectedCell.textLabel.text;
[[self delegate] selectedCell:cellTitle];
[self dismissModalViewControllerAnimated:YES];
}
//Parent VC interface
#import "ANSearchGetawayFilterViewController.h"
#interface ANGetawayFilterViewController : UIViewController <ANSearchGetawayFilterDelegate>
{
NSString* _cellText;
}
//Parent VC Implementation
- (id)initWithNibName:(NSString*)nibNameOrNil bundle:(NSBundle*)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self)
{
// Custom initialization
ANSearchGetawayFilterViewController *search = [[ANSearchGetawayFilterViewController alloc] init];
search.delegate = self;
}
return self;
}
//delegate method
-(void)selectedCell:(NSString *)cellTitle
{
_cellText = cellTitle;
NSLog(#"cell text %#", _cellText);
}
the delegate method is never called and when is NSLog the _cellText else where it comes up as null...what am I doing wrong? Thanks!
You are most likely creating a new instance of ANSearchGetawayFilterViewController when you present it and not configuring the delegate on it.
When you called
ANSearchGetawayFilterViewController *search = [[ANSearchGetawayFilterViewController alloc] init];
search.delegate = self;
you created an instance of ANSearchGetawayFilterViewController and then set the delegate up correctly, but you never stored this instance of ANSearchGetawayFilterViewController anywhere. So later on when you come to present it you call again
ANSearchGetawayFilterViewController *search = [[ANSearchGetawayFilterViewController alloc] init];
which gives you a completely different instance, which you then need to configure again. For example
ANSearchGetawayFilterViewController *search = [[ANSearchGetawayFilterViewController alloc] init];
ANSearchGetawayFilterViewController *search1 = [[ANSearchGetawayFilterViewController alloc] init];
NSLog(#"%d", search1 == search);
#=> 0
To fix update your code to be
- (BOOL)textFieldShouldBeginEditing:(UITextField*)textField;
{
BOOL shouldBeginEditing = YES;
NSLog(#"text field should begin editing");
ANSearchGetawayFilterViewController *myANSearchGetawayFilterViewController = [[[ANSearchGetawayFilterViewController alloc] init] autorelease];
myANSearchGetawayFilterViewController.delegate = self; // <--- configure the delegate
[self presentModalViewController:myANSearchGetawayFilterViewController animated:YES];
[self closeAllPickers];
return shouldBeginEditing;
}
I wouldn't make it an ivar as the likelihood is you will present this viewController momentarily just to select some data and then get rid of it, so it is probably safe to discard it and make a new one each time.
Au contraire, the delegate method is being called (hence the NSLog()). However, _cellText is (null) because the value being passed in is nil, ergo selectedCell.textLabel.text.
Firstly, are you sure that the -selectedCell method is being called?
You can do this by putting an NSLog() before or after -tableViewDidSelectRow...
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
...
NSLog(#"TABLEVIEW DID SELECT ROW BEFORE -> %# <-", cellTitle);
[[self delegate] selectedCell:cellTitle];
NSLog(#"TABLEVIEW DID SELECT ROW DELEGATE CALLED");
...
}
Also, you might want to do some cleanup (optional)
Firstly, you are leaking in your initialisation method. Either set the ANGetawayFilterViewController as a property of the parent class using the delegate, or release it after you set the delegate.
Secondly, in the -tableViewDidSelectRow, your code assumes that the delegate has the -selectedCell method coded. If you don't have the method implemented, then the application will result in a crash. You can prevent this by checking to see if the delegate -respondsToSelector...:
if ([self.delegate respondsToSelector:#selector(selectedCell:)]) {
[self.delegate selectedCell:cellTitle];
}
Thirdly, the method of which is being called by the delegate to notify the parentViewController doesn't follow the general schema that delegate methods use, with the exception of -numberOfRowsInSection (UITableViewDelegate). Your method should contain the actual ANFilterGetawayViewController instance too:
- (void) filterGetawayViewController:(ANSearchGetawayFilterViewController *) controller didSelectCellWithTitle:(NSString *) title {
...
}
It can be called as such:
[self.delegate filterGetawayViewController:self didSelectCellWithTitle:cellTitle];
Are you using ARC? Because when the init function ends, your object (and it's reference to the delegate) are cleaned up. What happens if you make the search variable a global one (defining it in your header and initializing it in your code)?
Assuming you are using ARC:
You need to make a retained #property for your ANSearchGetawayFilterViewController instance. It will have been released by ARC by the time the delegate method is called. Do something like this.
#property (strong, nonatomic) ANSearchGetawayFilterViewController *search;
...
#synthesize search = _search;
- (id)initWithNibName:(NSString*)nibNameOrNil bundle:(NSBundle*)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self)
{
// Custom initialization
self.search = [[ANSearchGetawayFilterViewController alloc] init];
self.search.delegate = self;
}
return self;
}
Not related to your problem, but best practice is to check if the delegate actually implements the method you expect it to before calling it, like so:
if ([self.delegate respondsToSelector:#selector(selectedCell:)]) {
[self.delegate selectedCell:cellTitle];
}

Present view from delegate modally in iOS 5

I cannot seem to find this anywhere online. I have an add button in one of my views and I have hooked it up to an IBAction method called add. In my storyboard, I have created a view that has a form all set up on it. I have assigned a class to that view in the storyboard as well. That class is called AddItemViewController.
I am trying to present this view modally and then set the delegate to the view that called the AddItemViewController. However, all I get is an empty UITableViewController that shows up. Here is my code that I'm trying to use:
- (IBAction)add {
AddItemViewController *addItem = [[AddItemViewController alloc] init];
addItem.delegate = self;
[self presentModalViewController:addItem animated:YES];
}
Is there anything I'm missing? Why does it just show an empty table and not the view controller that I set up in the storyboard?
Here is the code from the AddItemViewController:
#interface AddItemViewController : UITableViewController <UITextFieldDelegate> {
}
#property (strong, nonatomic) IBOutlet UITextField *note;
- (void)save:(id)sender;
- (void)cancel:(id)sender;
#end
#implementation AddItemViewController
- (void)viewDidLoad {
}
- (IBAction)cancel:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
- (IBAction)save:(id)sender {
DbHandler *db = [[DbHandler alloc] init];
[db executeUpdate:self.note];
[self dismissViewControllerAnimated:YES completion:nil];
}
#end
Well, AddItemViewController inherits from UITableViewController, not UIViewController, so it makes sense that a UITableViewController is showing up.
You should initiate the AddItemViewController like this:
AddItemViewController *addItem = [[AddItemViewController alloc] initWithNibName:#"AddItemViewController"];

Passing NSString from one view to another view

I have 2 views that are sharing the same class files (.h and .m). In the first view, I have a UIPicker with a list of items and a button. If the user clicks the button, I want my second view to come up with the appropriate Picture (based on the item that was selected in the UIPicker).
My thinking was to set an NSString in the first view based on the selected item. Then when the user clicks the button to push the second view onto the screen, i could pass that string with the new view. I've been "googling" for awhile but I can't seem to wrap my finger around it. If it matters, I am using a Navigation Controller. Here is the code that is executed on the button click:
-(IBAction) viewPictures{
ViewControllerClass *sView = [[ViewControllerClass alloc] initWithNibName:#"ViewController2XIB" bundle:nil];
[self.navigationController pushViewController:sView animated:YES];
}
You can either add an NSString * property to the ViewControllerClass and set it after you init it (this would be the easiest), or you can create your own init method that takes a string and sets it there.
Option 1:
(place this in your .h file)
#interface ViewControllerClass : UIViewController {
NSString *someString;
}
#property (nonatomic, copy) NSString *someString;
#end
(Then in your .m file)
#implementation ViewControllerClass
#synthesize someString;
#end
Alter your code from above to this:
-(IBAction) viewPictures{
ViewControllerClass *sView = [[ViewControllerClass alloc] initWithNibName:#"ViewController2XIB" bundle:nil];
sView.someString = #"Whatever String you want";
[self.navigationController pushViewController:sView animated:YES];
}
Option 2:
(place this in your .h file)
#interface ViewControllerClass : UIViewController {
NSString *someString;
}
- (id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)nibBundle someString:(NSString *)SomeString;
#end
(Then in your .m file)
#implementation ViewControllerClass
- (id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)nibBundle someString:(NSString *)SomeString
{
if(self = [super initWithNibName:nibName bundle:nibBundle]) {
someString = [SomeString copy];
}
return self;
}
#end
Alter your code from above to this:
-(IBAction) viewPictures{
ViewControllerClass *sView = [[ViewControllerClass alloc] initWithNibName:#"ViewController2XIB" bundle:nil someString:#"Whatever String you want"];
[self.navigationController pushViewController:sView animated:YES];
}
Put a NSString in the .m that shares these 2 views, like Chris said.
In the method that responds to the button click pass the string from the uipicker to the NSString you created and then pass it to the view 2.

How to assign managedObjectContext to a dynamic viewController?

I have 4 buttons on main screen, each one sends me to a viewController. The third one, sends me to a view on which I wanna set the managedObjectContext. If I use the class name to create an instance, it's all right. But I'm looking for a way to use just one method that uses an array to retrieve the name of the Class for the needed viewController. But it's leading to an error message, like it doesn't exist on the destination viewController??? Anyone have any ideas about this aproach??? Thanks in advance!
Here is the code:
NSArray *viewControllers = [[NSArray alloc]
initWithObjects:#"nil",#"OpcoesView",#"nil",#"TheNames", nil];
NSString *viewName = [viewControllers objectAtIndex:[sender tag]]; //the taped button tag
UIViewController *viewController = [[NSClassFromString(viewName) alloc]
initWithNibName:viewName bundle:nil];
if ([sender tag] == 3) {
viewController.managedObjectContext = contexto;
}
You do not need to know the subclass at all. Because Objective-C is a dynamic language and messages are resolved at runtime, you can send the message without having to know anything about the subclass at all.
First I would refer to the subclass as an id (instead of UIViewController) and as long as you have its header imported you can call [viewController setManagedObjectContext:contexto] directly.
However if you don't want to or can't import the header then just use KVC as follows:
[viewController setValue:contexto forKey:#"managedObjectContext"];
I would keep MOC in my app delegate instead of assigning it down to every of my viewControllers:
And in my viewController .m file:
#import "MyAppDelegate.h" // Assuming you have a property called managedObjectContext in your MyAppDelegate
#interface MyViewController (PrivateMethgods)
#property (nonatomic, readonly) NSManagedObjectContext * managedObjectContext;
#end
#implementation MyViewController
#dynamic managedObjectContext
- (NSManagedObjectContext *)managedObjectContext {
MyAppDelegate *appDelegate = (MyAppDelegate *)[UIApplication sharedApplication].delegate;
return appDelegate.managedObjectContext;
}
So I can use it in my viewController like this:
if ([self.managedObjectContext hasChanges]) {
...
}
To set a property that is only in the subclass view controller (such as "managedObjectContext"), you can take advantage of the fact that you know the type like this:
NSArray *viewControllerNames = [[NSArray alloc] initWithObjects:#"nil",#"OpcoesView",#"nil",#"TheNames", nil];
NSString *viewControllerName = [viewControllerNames objectAtIndex:[sender tag]]; //the tapped button tag
UIViewController *viewController = [[NSClassFromString(viewControllerName) alloc] initWithNibName:viewControllerName bundle:nil];
if ([sender tag] == 3) {
TheNames *namesVC = (TheNames*)viewController;
namesVC.managedObjectContext = contexto;
}