How data passes from view controller to another view controller - ios

Code:
[[UIApplication sharedApplication] delegate];
Through this code how to pass data from one to another.

Basically there is only one instance of 'sharedApplication' (it is a singleton), which means that instances of view controllers that are independent of each other can still talk to the same data object. You can therefore write methods in your sharedApplication delegate which can effectively allow these two view controllers to communicate. For more information please see the Apple documentation.
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIApplication_Class/

You can use the segue destination view controller for transfar data between controllers.Suppose you have one TextField in one View Controller and you want to pass the Textfield text to another viewController.Then use this it might be helpful.
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
TargetViewController *tvc; //Second view controller Object
tvc = [segue destinationViewController];
tvc.lonetxt = fname.text; //use properties of another view using . operator
tvc.ltwotxt = lname.text;
tvc.lthreetxt = age.text;
tvc.lfourtxt = college.text;
}

Try following:
Interface in Your AppDelegate:
#interface MyAppDelegate : NSObject {
NSString *myString;
}
#property (nonatomic, retain) NSString *myString;
...
#end
and in the .m file for the App Delegate you would write:
#implementation MyAppDelegate
#synthesize myString;
myString = some string;
#end
Then, in viewcontroller.m file you can fetch:
MyAppDelegate *appDelegate = (MyAppDelegate*)[[UIApplication sharedApplication] delegate];
someString = appDelegate.myString; //..to read
appDelegate.myString = some NSString; //..to write

Related

Passing data from the FirstViewController to the LastViewController

I have four viewControllers in my current design and I am designing an app to sell a product.
FirstViewController gets the product image and when user clicks to the next button then it takes user to the secondviewcontroller where user describes the product and then user clicks next button which takes user to the thirdViewcontroller where price and condition are entered. In the lastviewcontolller there is a post button to send the product info to the server. I am using POST method.
The following segue approach does not fit into what I want, because it sends the firstviewcontroller object (product image) to the secondviewcontoller, and then secondviewcontroller also should forward the product image to the thirdviewcontoller and so on. I do not think it is a feasible way of doing it.
I wonder what is the best way of collection information from the first page till to the last page and send it. What is best way of handling that issue? I am using segue between the viewcontrollers.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Make sure your segue name in storyboard is the same as this line
if ([[segue identifier] isEqualToString:#"isSecond"])
{
// Get reference to the destination view controller
SecondViewController *vc = [segue destinationViewController];
// Pass any objects to the view controller here, like...
[vc setMyProductImage:productImage];
}
}
Please don't use a singleton, even if the majority of users here tells you so. It would violate the SOLID-Principles for several reasons.
Instead just pass the object from ViewController to ViewController.
If all ViewController expect the same model class, you can create a common base class that has the property for the model.
it could have this method
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.destinationViewControler isKindOfClass:[ProductAwareBaseViewController class]])
{
ProductAwareBaseViewController *vc = (ProductAwareBaseViewController *)segue.destinationViewControler;
vc.product = self.product;
}
}
I created an example project: https://github.com/vikingosegundo/ProductWizard
Note, that all view controller derive from ProductAwareBaseViewController
#import UIKit;
#class Product;
#interface ProductAwareBaseViewController : UIViewController
#property (nonatomic, strong) Product *product;
#end
#import "ProductAwareBaseViewController.h"
#import "Product.h"
#interface ProductAwareBaseViewController ()
#end
#implementation ProductAwareBaseViewController
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.destinationViewController isKindOfClass:[ProductAwareBaseViewController class]]) {
ProductAwareBaseViewController *vc = (ProductAwareBaseViewController *)segue.destinationViewController;
vc.product = self.product;
}
}
#end
This ViewController knows how to pass the model data of class Product to other instances of ProductAwareBaseViewController and subclasses of it.
All other view controller don't deal with passing the data, just adding each portion of data (name, description, price) to the model and displaying it.
i.e:
#import "EditNameProductViewController.h"
#import "Product.h"
#interface EditNameProductViewController ()
#property (weak, nonatomic) IBOutlet UITextField *nameField;
#end
#implementation EditNameProductViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.product = [[Product alloc] init];
}
- (IBAction)continueTapped:(id)sender {
self.product.productName = self.nameField.text;
}
#end
#import "EditDescriptionProductViewController.h"
#import "Product.h"
#interface EditDescriptionProductViewController ()
#property (weak, nonatomic) IBOutlet UITextField *descriptionField;
#property (weak, nonatomic) IBOutlet UILabel *nameLabel;
#end
#implementation EditDescriptionProductViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.nameLabel.text = self.product.productName;
}
- (IBAction)continueTapped:(id)sender {
self.product.productDescription = self.descriptionField.text;
}
#end
Create an object to act as your application's data model. It can be a singleton or it can be a normal object that's available from a known location...such as owned by the app delegate.
Update your model when you have new information and read from the model when you need to display something. Using prepareForSegue: and linking controllers may be acceptable for simple things but it really doesn't scale well.
One way of doing this would be that you create a mutable dictionary (or a custom object with variables) in the first view controller. Then you would pass a weak reference to second/third/fourth view controllers of the mutable dictionary/object from first view controller. Each view controller would be able to set data to the dictionary/object and the last one would be able to process the information.
Another way would be to create a simple singleton class with variables that you want to store. The first view controller would reset the singleton variables. Then let each view controller access the singleton and store their values there, last view controller would process values from singleton.
It depends how many data you are collecting and what you personally prefer.

addObject to NSMutableArray is nil even after initialization?

I have an NSMutableArray declared as property in .h and initialized in viewDidLoad in my SPOCVC .m (UIViewController)...
#property (strong, nonatomic) NSMutableArray* SPOCTrackList;
in viewDidLoad
if ([self SPOCTrackList] == nil) {
self.SPOCTrackList = [[NSMutableArray alloc]init];
NSLog(#"SPOTTrackList INITIALIZED");
}
In a separate VC, I'm trying to pass/addObject to SPOCTracklist...
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
SCTrack* selectedTrack = self.trackList[indexPath.row];
[[[SPOCVC sharedInstance]SPOCTrackList]addObject:selectedTrack];
NSLog(#"%lu", (unsigned long)[[[SPOCVC sharedInstance]SPOCTrackList]count]);
So my NSMutableArray is initialized and I can add dummy objects, but why can't I pass it from another VC using singleton or anything, such as...
SPOCVC* spocVC = self.tabBarController.viewControllers[2];
[spocVC.SPOCTrackList addObject:selectedTrack];
Thanks for pointing me in the right direction.
View controllers are only intended to be around while they are on screen. They are not a place to store data. Generally when one view controller talks directly to another view controller that it didn't create, you're doing something wrong.
Move SPOCTrackList to your model and have both view controllers talk to it rather than to each other.
There should never be a "sharedInstance" on a view controller. That's a sure sign that you're abusing the view controller as the model.
What's probably happening in your particular case is that viewDidLoad is running on a completely different SPOCVC than your sharedInstance.
why not use appdelegate to handle this
appdelegate.h
//add property to hold the reference
#property (nonatomic, copy) NSMutableArray *referenceArray;
//share the app delegate
+(AppDelegate *)sharedAppDelegate;
#end
in appdelegate.m
//synthesize the property
#synthesize referenceArray;
//return the actual delegate
+(AppDelegate *)sharedAppDelegate {return (AppDelegate *)[UIApplication sharedApplication].delegate;}
in viewdidload method
//add the delegate
import "appdelegate.h"
//init the array
self.SPOCTrackList = [[NSMutableArray alloc]init];
//Add reference
[AppDelegate sharedAppDelegate].referenceArray = self.SPOCTrackList;
and add anywhere like this
import "appdelegate.h"
[[AppDelegate sharedAppDelegate].referenceArray addobject:object];

Sharing a variable between ViewControllers

I have an iPhone app with three pages, each of which allows the user to enter some text. On the final page I want to concatenate all three strings and print it out. I have a UIViewController (named PageXController) for each page and I am trying to pass variables along to the final page. The method I currently try doesn't quite work. Here is an example:
I begin by declaring a string as an instance variable in PageThreeController.h
#interface PageThreeController : UIViewController{
NSMutableString *string;
}
#property (nonatomic) NSMutableString *string;
Next I add the following to PageOneController.h,
#import "PageThreeController.h"
#interface PageOneController : UIViewController
#property (nonatomic) PageThreeController *pageThree;
In PageOneController I then attempt to set the string instance variable on page three;
- (IBAction)handleButton:(id)sender {
_pageThree = [[PageThreeController alloc] init];
_pageThree.from = [[NSMutableString alloc]init];
[_pageThree.from appendString:#"Hello World"];
NSLog(#"My string is %# on page one.", _pageThree.from);
}
The NSLog prints out My string is 'Hello World' on page one. but when I add the same NSLog on PageThreeController.m before concatenating, 'string' is NULL.
It seems that I am making a separate copy of the pageThreeViewController. What do I need to do to change the actual value of string on page three? I am really new at this
The easiest way to pass data between ViewControllers is using the AppDelegate, even though
there is other methods .
Method 1 - using AppDelegate.
Add the following line in your Appdelegate.
#property (strong,nonatomic) NSMutableString *str;
To access the variable from any view controller,
MyAppdeleagte appDelegate=[[UIApplication sharedApplication]delegate];
NSMutableString *Stringdata=appDelegate.str;
Method 2 -Specifying objects.
in this method , you can proceed as you are now doing and, just need to specify the
view controller instance.
let you have are navigating from one controller to another , say FirstController to Second.
Firstcontroller.h
#interface FirstController : UIViewController{
NSMutableString *string;
}
#property (nonatomic) NSMutableString *string;
SecondController.h
#interface SecondController : UIViewController{
}
#property (strong,nonatomic) FirstController *firstScreen;
Within your implementation of the FirstController, before you navigate to the SecondController ,you have to specify the instance in SecondController.
in FirstController.m
SecondController *nextScreen=[self.storyboard instantiateViewControllerWithIdentifier:#"SecondView"];
nextScreen.firstScreen=self;
Then in your SecondController.m , you can simply get the String as
_firstScreen.string;
Customize your prepareForSegue method in order to pass necessary vars through public properties of these controllers.
For example:
#pragma mark - PreparaForSegue
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"goToDetail"]) {
YourDestinationController *destinationController = segue.destinationViewController;
destinationController.myString = self.myStringToPass;
}
}
Where myString is a public property in YourDestinationController and myStringToPass is a property in your source controller (it could be in private scope)
If you need to access it from anywhere, you could store the variable in the AppDelegate. So if you had a variable like this in your AppDelegate:
#property (nonatomic) NSString *currentStringToPass;
Then you could access it from your ViewControllers by using the following code:
- (IBAction)handleButton:(id)sender {
AppDelegate *app = (AppDelegate *)[[UIApplication sharedApplication] delegate];
_pageThree = [[PageThreeController alloc] init];
_pageThree.from = [[NSMutableString alloc]init];
[app setCurrentStringToPass:#"Hello World"];
NSLog(#"My string is %# on page one.", [app currentStringToPass]);
}

How to get the value of NSMutableArray in viewcontroller from the appdelegate

I have the NSMutableArray property in ViewController.h Now i want to get this Array value from appdelegate.
Is it possible can anyone help me to do that.
In viewcontroller.h
#property (nonatomic, retain) NSMutableArray *fullImg;
In viewcontroller.m
#synthesis fullImg;
I also assigned values for fullImg. Now i want to get that value in app delegate.
Thanks in advance.
Move the array declaration from viewController to AppDelegate
In viewController.m do:
top file:
#import "AppDelegate.h"
in place you want to use the array:
AppDelegate *ap = [[UIApplication sharedApplication] delegate];
ap.fullImg // -> USE IT HOW YOU WANT
...
You can put the whole NSMutableArray into NSUserDefaults with a key e.g.
In app delegate:
NSUserDefaults *def=[NSUserDefaults StanderUserDefaults];
[def setObject:fulImg forKey:#"ImageArray"];
In ViewController class:
NSUserDefaults *def=[NSUserDefaults StanderUserDefaults];
NSMutableArray *yourimgarry=[def valueForKey:#"ImageArray"];
When you create the object for viewController class, you can pass the array reference to the viewController by creating new custom constructor. i.e,
//in appdidFinishLaunchingWithOptions
ViewController *viewController = [[ViewController alloc] initWithArray:fullImgArray];
self.window.rootViewController = viewController;
// In ViewController.h
- (id)initWithArray:(NSMutableArray *)fullImgArray;
// In ViewController.m
- (id)initWithArray:(NSMutableArray *)fullImgArray
{
self = [super init];
if (self)
{
self.fulImg = fullImgArray;
}
return self;
}
There are two possibilities.
Using appDelegate. Use a property in app delegate to pass data between ViewContriollers
and AppDelegate.
in first controller
MyAppdeleagte appDelegate=[[UIApplication sharedApplication]delegate];
appDelegate.fullImg=dataToPass;
in the second controller
MyAppdeleagte appDelegate=[[UIApplication sharedApplication]delegate];
data=appDelegate.fullImg;
in AppDelegate
self.fullImg=data;
2.Specifying object Instance.
in your ViewController after allocating the AppDelegate , specify that the object instance in the current viewController is same as the one in AppDelegate. For this declare a NSMutableArray property in AppDelegate.
in AppDelegate.h
#property NSMutableArray *fullImg;
in ViewController.h
MyAppdeleagte appDelegate=[[UIApplication sharedApplication]delegate];
appDeleagte.fullImg=self.fullImg;

iOS Getter and Setter confusion

I think that I am a bit confused about iOS #property getter and setters. I am trying to set an NSString iVar in my AppDelegate.h file from another class so that it can be used by all of the classes in the project?
For example, I am working on an iPhone project that stores an iVar NSString *currentUser in AppDelegate.h. I need to be able to set this through one method in a ViewController.m and then get it through another method in a second ViewController?
Maybe Getter and Setter is the wrong direction of attack all together? I understand that i don't want to alloc init the AppDelegate as the iVar will only exist in that object and I want it accessible to ALL objects in ALL classes?
Please someone set me straight.
All the best,
Darren
Here's the setup for the app delegate.
#interface AppDelegate
{
NSString *__currentUser;
}
#property (monatomic, copy) NSString* currentUser;
#end
#implementation AppDelegate
#synthesize currentUser = __currentUser;
- (void) dealloc
{
[__currentUser release];
[super dealloc];
}
#end
From one view controller, you could set a value for the current user, and from a subsequent view controller, get that value for some nefarious purpose.
#implementation LoginController
- (void) viewDidLoad
{
...
AppDelegate *bob = [[UIApplication sharedApplication] delegate];
[bob setCurrentUser: #"Jim Kirk"];
...
}
#end
In some other view controller that appears later, the value of the current user can be accessed.
#implementation ProfileViewController
- (void) viewDidLoad
{
...
AppDelegate *bob = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSString * user = [bob currentUser];
// insert nefarious purpose for current user value here
...
}
#end

Resources