Objective-C iPhone data between classes - iphone

Here is my situation. I have ViewController class A with a button that goes to TableViewController class B by doing the following.
- (void) goToClassB
{
ViewControllerB *viewController =
[[ViewControllerB alloc] initWithStyle:UITableViewStylePlain];
// Present view controller modally.
if ([self
respondsToSelector:#selector(presentViewController:animated:completion:)]) {
[self presentViewController:viewController animated:YES completion:nil];
} else {
[self presentModalViewController:viewController animated:YES];
}
}
I want to be able to have an array that can be accessed and edited by both class A and class B. How can I achieve this?

Create a Array variable in Class B like:
#interface classB:NSObject
{
NSMutableArray *arrayFromA;
}
#property (nonatomic, assign) NSMutableArray *arrayFromA;
Synthesize the variable.
And in this method pass the array like:
- (void) goToClassB
{
ViewControllerB *viewController = [[ViewControllerB alloc] initWithStyle:UITableViewStylePlain];
[viewController setArrayFromA:yourArray];
// Present view controller modally.
if ([self
respondsToSelector:#selector(presentViewController:animated:completion:)])
{
[self presentViewController:viewController animated:YES completion:nil];
}
else
{
[self presentModalViewController:viewController animated:YES];
}
}

Create a NSMutableArray in ViewControllerA and pass it to ViewControllerB after your allocation.

This can be achieve Creating NSMutableArray And And Make it in Property assign in one of the class
#property(nonatomic,assign) NSMutableArray *array;

I mention that you want edit by both so.You can use application delegation for sharing app level variable. Check this link.
Some code is here. In your app delegate class.
#interface YourDelegateClass:UIResponder
{
NSMutableArray *array;
}
#property (nonatomic, assign) NSMutableArray *array;
You can access that array from everywhere of your app class with this code
YourDelegateClass * delegate =[[UIApplication shareApplication]delegate];
yourclassa.array = delegate.array;
or yourclassb.array = delegate.array;
Note: your must alloc *delegate.array* on your prefer at class or your delegate.

Create NSMutable array in view1 set property
#property(nonatomic,assign) NSMutableArray *array;
Create same array in viewB and set property and
#property (nonatomic, assign) NSMutableArray *arrayB;
#Synthesize that
Now at the time call viewB set value of array of viewA to viewB like this
ViewControllerB *viewController = [[ViewControllerB alloc] initWithStyle:UITableViewStylePlain];
[viewController arrayB:array];

The simplest way would, just as others point out, be simply passing the array to B by setting a property, but one other option would be to let B have a weak back reference to A. Thus you're always using the same array. This could be useful if A and B are changing the array at the same time.
#interface ViewControllerA : UIViewController
#property (nonatomic, strong) NSArray *array;
#end
#interface ViewControllerB : UIViewController
#property (nonatomic, weak) ViewControllerA *viewControllerA;
#end
/* When you're creating the ViewControllerB, do this: */
...
viewController.viewControllerA = self;
...
/* Use the array (From ViewControllerB) */
- (void)doSomethingWithTheArray
{
self.viewControllerA.array = ...
}

Related

How to pass data between not neighbor view controllers in Storyboard

I've stuck in the problem.
I have a storyboard with several view controllers.
What I need to do is:
I need to pass an array from FirstViewController to SecondViewController (they are not neighbors and are not connected via segue) where PikerView will upload the array. After that the picked result should be passed to ThirdViewController.
I have tabbed applicateion where FirstViewController and SecondViewControllers are connected to Tab Bar View Controller and ThirdViewController is connected with SecondViewController via Push Segue.
See how I try to pass data form First to Second
CategoryExpencesViewController.h
#import <UIKit/UIKit.h>
#import "AddCategoryViewController.h"
#import "CategoryPickerViewController.h"
#interface CategoryExpencesViewController : UITableViewController <AddCategoryViewControllerDelegate>
#property(nonatomic, weak) IBOutlet UIBarButtonItem *editButton;
#property(nonatomic, strong) NSMutableArray *categories; //list of category items
#property(nonatomic, strong) NSMutableArray *listOfCategories; //list of category names
CategoryExpencesViewController.m
-(void)updateArray
{
CategoryPickerViewController *controller = [[CategoryPickerViewController alloc]init];
controller.categoryList = [[NSMutableArray alloc]init];
controller.categoryList = listOfCategories;
NSLog(#"%d", [listOfCategories count]);
NSLog(#"%d", [controller.categoryList count]);
}
I think you need this
Use your's Push Segue.
segue.sourceViewController (or self) will point at SecondViewController.
segue.sourceViewController.tabBarController will point at Tab Bar Controller.
From Tab Bar Controller you will find your's FirstViewController.
I suppose you would have solved it, but i post this just for the record:
Wrap the array into a class, and make it have a static construction method:
Wrapper.h:
#property (nonatomic, strong) NSMutableArray* array;
+(Wrapper*)createArray;
Wrapper.m:
+(Wrapper*)createArray{
static Wrapper* instance = nil;
if (instance == nil) {
instance = [[Wrapper alloc] init];
//Your initialization code for the array
}
return instance;
}
Then, in your FirstViewController:
-(void)updateArray{
CategoryPickerViewController *controller = [[CategoryPickerViewController alloc]init];
controller.categoryList = [[NSMutableArray alloc]init];
controller.categoryList = [[Wrapper createArray] array];
NSLog(#"%d", [listOfCategories count]);
NSLog(#"%d", [controller.categoryList count]);
}
As this is the first call to Wrapper, the array is generated.
Then in your SecondViewController, when you call:
secondView.categoryList = [[Wrapper createArray] array];
and you obtain the same array as in FirstViewcontroller.
have you thought of NSUserDefault try it and you can also create a instance global variable in AppDelegate class and access it by creating an instance of AppDelegate in any other ViewController but i think NSUserDefault is the best option from all.

How to use NSString from NSObject class in multiple Classes (View Controllers) [duplicate]

This question already has answers here:
What's the best way to communicate between view controllers?
(4 answers)
Closed 9 years ago.
I have NSObject class that has a NSString called tweetTitle;
TweetDesc.h file
#import <Foundation/Foundation.h>
#interface TweetDesc : NSObject
#property (strong, nonatomic) NSString * tweetTitle;
-(void) setFullTweetTitle:(NSString *) fullTweetTitle;
#end
TweetDesc.m file
#implementation TweetDesc
#synthesize tweetTitle;
-(void) setFullTweetTitle:(NSString *) fullTweetTitle
{
self.tweetTitle = fullTweetTitle;
}
#end
I have three classes (View Controllers), FirstViewController, SecondViewController and ThirdViewController.
Here are the code of FirstViewController
FirstViewController.h
#interface TweetViewController : UIViewController <UITextViewDelegate>
#property (strong, nonatomic) NSString * tweet;
#property (weak, nonatomic) IBOutlet UITextView *tvTweetTitle;
- (IBAction)btnCreateTweet:(id)sender;
#end
FirstViewController.m
#implementation TweetViewController
#synthesize tvTweetTitle, tweet;
- (void)viewDidLoad
{
[super viewDidLoad];
self.tvTweetTitle.delegate = self;
}
- (IBAction)btnCreateTweet:(id)sender
{
tweet = [[NSString alloc]initWithFormat:#"%#", tvTweetTitle.text];
TweetDesc * td = [[TweetDesc alloc]init];
[td setFullTweetTitle:tweet];
SecondViewController * svc = [self.storyboard instantiateViewControllerWithIdentifier:#"SecondViewController"];
[self.navigationController pushViewController:ivc animated:YES];
}
My Question is: How can I use tweetTitle in Second and third ViewController without creating new instance of TweetDesc class and set again the tweetTitle in every ViewControler.
In the second view controller I tried:
TweetDesc * td = [[TweetDesc alloc]init];
NSLog(#"%#", td.tweetTitle);
but I get null, it seems that it was released already or something else.
Thanks for the help in advance.
Just give SecondViewController a TweetDesc property, like this:
#interface TweetDesc : UIViewController
#property (nonatomic, strong) TweetDesc *tweetDesc;
...
Then, after you instantiate a SecondViewController, set its tweetDesc property:
SecondViewController * svc = [self.storyboard instantiateViewControllerWithIdentifier:#"SecondViewController"];
svc.tweetDesc = td;
[self.navigationController pushViewController:svc animated:YES];
In your SecondViewController implementation, use self.tweetDesc to access the instance.
First thing you don't need a class for a single property use the string only. There are several ways of doing this.
First you can have a tweet property globally defined in AppDelegate.
You can pass the variable reference from one to another viewcontrolleres.
Or, you can use NSUserDefaults to set and get the text.
In your case first one is more useful. Just do as follows
In AppDelegate.h
Define a property as NSString *tweetText;
Now in you action
- (IBAction)btnCreateTweet:(id)sender
{
AppDelegate *appDelegate=(AppDelegate *)[[UIApplication sharedApplication] delegate];
appDelegate.tweetText=tvTweetTitle.text;
}
Then in any controller you want to access the value just use
AppDelegate *appDelegate=(AppDelegate *)[[UIApplication sharedApplication] delegate];
NSLog("%#",appDelegate.tweetText);
Same approach can be used for NSUserDefaults as to set value
[[NSUserDefaults standardUserDefaults] setObject:tvTweetTitle.text forKey:#"Tweet"];
[[NSUserDefaults standardUserDefaults] synchronize];
and to get
NSLog("%#",[[NSUserDefaults standardUserDefaults] valueForKey:#"Tweet"]);
Make sure you set the values before navigating to other controllers..
The above should solve your purpose..
Based on your comment I feel you want each of your view controllers to hold a TweetDesc object. For that you could have a base class like
#interface baseViewController:UIViewController
#property(strong, nonatomic)TweetDesc *td;
#end
All your viewcontrollers should derive from this base class. So that your controllers definition look like this -
#interface FirstViewController:baseViewController
...
#end
#interface SecondViewController:baseViewController
...
#end
#interface ThirdViewController:baseViewController
...
#end
U instantiate it in the FirstViewController -
TweetDesc * td = [[TweetDesc alloc]init];
[td setFullTweetTitle:#"whatever string you want"];
And pass it on to SecondViewController - //like in Rob Mayoff's answer
SecondViewController * svc = [self.storyboard instantiateViewControllerWithIdentifier:#"SecondViewController"];
svc.tweetDesc = td;
[self.navigationController pushViewController:svc animated:YES];
INSIDE SecondViewController you may refer it as self.tweetDesc. And pass it on to whichever viewcontroller you want after this using the above code.
ThirdViewController *third= [self.storyboard instantiateViewControllerWithIdentifier:#"ThirdViewController "];
third.tweetDesc = self.tweetDesc;
[self.navigationController pushViewController:third animated:YES];
Pass it on the ANY viewcontroller just make sure it's base class is the baseClassViewController.
You need to use category of TweetDesc where you create method that adds your default title. Or you can create singleton of TweetDesc that will always hold one title.
In your ViewController create a method called initWithTweetDesc. The method will look like this:
- (id)initWithTweetDesc:(TweetDesc*)tweet
{
self = [super init];
if (self) {
_tweet = tweet;
}
return self;
}
Now, when you want to move to the new view controller, run this code:
TweetViewController *vc = [[TweetViewController alloc] initWithTweetDesc:tweetDesc];
[self.navigationController pushViewController:vc animated:YES];
You can use your AppDelegate for this.
eclare the property #property(nonatomic, strong) TweetDesc * td; in AppDelegate.h file.
And change the method like:
- (IBAction)btnCreateTweet:(id)sender
{
tweet = [[NSString alloc]initWithFormat:#"%#", tvTweetTitle.text];
TweetDesc * td = [[TweetDesc alloc]init];
[td setFullTweetTitle:tweet];
[[[UIApplication sharedApplication] delegate] setTd:td];
SecondViewController * svc = [self.storyboard instantiateViewControllerWithIdentifier:#"SecondViewController"];
[self.navigationController pushViewController:ivc animated:YES];
}
And in your second and third view controllers you can get the value using:
TweetDesc *desc = [[[UIApplication sharedApplication] delegate] td];
NSLog(#"%#",desc.fullTweetTitle);

UI is not updating while sending data from another view controller on UITabBar?

i am using UITabBar to display two viewControllers, firstViewController is a uiview and secondViewController is a table view. what my need is when i clicked the second view table cell, the value should be updated on UILabel of firstViewController.
my code is here,
In secondviewcontroller.h
#interface firstviewcontroller {
NSMutableArray *stationnamestobepassed;
}
#property (nonatomic, retain) NSMutableArray *stationnamestobepassed;
#end
In secondviewcontroller.m declare this
#implementation firstviewcontroller
#synthesize stationnamestobepassed;
-(void) someaction{
stationnamestobepassed = [NSMutableArray
arrayWithObjects:#"string1",#"string2",#"string3"];
secondviewcontroller = [[secondviewcontroller alloc]initWithNibName:#"NIbName"
Bundle:nil];
secondviewcontroller.stationnamespassed = self.stationnamestobepassed;
//i am not pushing the view controller.
}
#end
In firstviewcontroller.h declare this
#interface secondviewcontroller {
NSMutableArray *stationnamespassed;
}
#property (nonatomic, retain) NSMutableArray *stationnamespassed;
#end
In firstviewcontroller.m declare this
#implementation secondviewcontroller
#synthesize stationnamespassed;
-(void)viewWillAppear:(BOOL)animated
{
//stationNameDisplay is a uilabel
stationNameDisplay.text=[stationnamespassed objectAtIndex:0];
NSLog(#"station name %#",[stationnamespassed objectAtIndex:0]);
}
-(void) dealloc{
[stationnamespassed release];
[super release];
}
#end
problem is , value is not updating and it gives NULL. but i tried with pushing the first vie and it works. actually i don't want to push that view controller because i was already exist on tab.
your view will appear called out when you select the tab. while this line makes a new object of that controller, not that of tab controller.
secondviewcontroller = [[secondviewcontroller alloc]initWithNibName:#"NIbName"
Bundle:nil];
to do what you want. you will have to do some thing like this
UINavigationController* navController = [[self.tabBarController viewControllers] objectAtIndex:/*your tab index on which desiredControllerResides*/];
NSArray* viewControllers= [navController viewControllers];
for(UIViewController *theController in viewControllers)
{
if([theController isKindOfClass:[secondviewcontroller]])
{
theController.stationnamespassed = self.stationnamestobepassed;
//i.e this line of your code secondviewcontroller.stationnamespassed = self.stationnamestobepassed;
}
}

Assign value to textfield firstview take of secondview

I have two views in my application: in main view there are input fields that the user must fill and a button connected to the second view. In the second view there is a table view, when the user selects a row automatically returns to the main view.
My problem is that when you return to the main view the values ​​of text fields are cleared.
Any solutions?
Thank you.
Second View header
#class MainViewController;
#interface ListaViewController : UIViewController
<UITableViewDataSource, UITableViewDelegate, UISearchBarDelegate>
{
UITableView *table;
UISearchBar *search;
MainViewController *child;
}
#property (nonatomic, retain) IBOutlet UITableView *table;
#property (nonatomic, retain) IBOutlet UISearchBar *search;
#property (nonatomic, retain) MainViewController *child;
- (IBAction)switchBack:(id)sender;
Second View Implementation:
-(IBAction)switchBack:(id)sender
{
child.selectedCountry = selectedCountry;
child.codiceComune = codiceComune;
[self.navigationController popViewControllerAnimated:YES];
}
First View:
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
cityField.text = selectedCountry;
}
This not work!
-(IBAction)switchBack:(id)sender
{
MainViewController *controller = [[MainViewController alloc] initWithNibName:#"MainViewController" bundle:nil];
controller.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:controller animated: YES];
[controller release];
}
It means you create new MainViewController, not return to previous.
Use this code instead
-(IBAction)switchBack:(id)sender
{
[self dismissModalViewControllerAnimated:YES];
}
P.S. It works if you go to the second vievcontroller same way, as you write in -(IBAction)switchBack:(id)sender
As a guess without code, you're probably emptying or initialising your text fields in viewDidLoad, viewDidAppear or viewWillappear - do it in your viewController init instead.

Calling a function from another UIViewController

I'm a beginner programmmer, this is for xcode - iPhone. although i made alot of my iPhone app but i seem to lack some understanding of how a simple communication might work.
Specially when I've got 2 ViewControllers.
And I wana call one function of a ViewController from another ViewController. Both are under a tabbarController. What I want to achieve is When I'm in ViewA, after tapping on a tableCell, I Should Invoke a method of ViewB and the NavigationBar of ViewB pushes to viewDetail.
The Following is the code i'm using
in ViewControllerA.h (where I'm calling a method)
#class ViewControllerB;
#interface SmartDDxViewController : UIViewController {
IBOutlet UITableView *tableView;
ViewControllerB *xViewController;
}
#property (nonatomic, retain) UITableView *tableView;
#property (nonatomic, retain) ViewControllerB *xViewController;
And this is what I use to invoke it..ViewControllerA.m
ViewControllerB *ddViewController = [[ViewControllerB alloc] init];
self.xViewController = ddViewController;
[xViewController InitialiseDetailWithId:2 title:#"HEYA"];
Heres the InitialiseDetailWithId code: in ViewControllerB.m
-(void)InitialiseDetailWithId:(NSInteger)pkey title:(NSString *)tt{
NSLog(#"InitialiseDetailC=========================================");
AppDelegate *appDelegate = (Smart_DifferentialsAppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate GetConditionDetailsWithId:pkey];
DDisViewController *viewController= [[DDisViewController alloc] initWithNibName:#"DetailView" bundle:nil];
viewController.title = tt;
[self.NavBar pushViewController:viewController animated:YES];
//[tt release];
[viewController release];
viewController = nil;
[self say:#"HEYA"]; //this is ALERTVIEW box that displays HEYA
}
I'm getting all information fine, and the alertview does get displayed. But when I chose that View in TabBar, its not pushed.
Do not use direct access between view controllers, instead use the delegate pattern. Define your controller like this:
#protocol ViewControllerAInitDelegate;
#interface ViewControllerA : UIViewController {
IBOutlet UITableView *tableView;
id<ViewControllerAInitDelegate> initDelegate;
}
#property (nonatomic, retain) UITableView *tableView;
#property (nonatomic, assign) ViewControllerAInitDelegate *initDelegate;
#end
#protocol ViewControllerInitDelegate
-(void)initializeDetailWithId:(NSInteger)pkey title:(NSString)tt;
#end
So in
Now let your application delegate conform to the ViewControllerInitDelegate protocol. It should look something like this:
#interface AppDelegate : NSObject <UIApplicationDelegate, ViewControllerInitDelegate> {
IBOutlet UITabBarControler* tabBarController;
IBOutlet ViewControllerA* controllerA;
IBOutlet ViewControllerB* controllerB;
}
#end;
The AppDelegate should know about both ViewControllerA, and ViewControllerB, but neither of the view controller should know about each other. This way it will be much easier to debug and extend your app.
//current view controller index
int currentVCIndex = [self.navigationController.viewControllers indexOfObject:self.navigationController.topViewController];
//previous view controller (index -1)
AccountViewController *account = (AccountViewController *)[self.navigationController.viewControllers objectAtIndex:currentVCIndex - 1];
(access to anything you want)
account.property = object;
[account doSmthng];
In each of your view controllers, you might want to add a instance variable/property to keep track of the other view controller.
you might have for example:
#interface ThisViewController : UIViewController {
SomeViewController *sViewController;
// other instance variables
}
#property (nonatomic, retain) SomeViewController *sViewController;
This not only makes it easier to call methods from the other view controller and access its public properties, but it also allows you an easier way of flipping between the two (with or without animation).