transfer data from one view controller to another view controller - ios

if I fill state,province and town in first view controller, how to get just town or town and state in another view controller, when I press OK button.
http://i.stack.imgur.com/jhwGq.png

First of all, you should create a property in the SecondVC.h to receive de text and a property linked to the label in screen:
#property(nonatomic, copy) NSString *townText;
#property (weak, nonatomic) IBOutlet UILabel *townLabel;
After that, in the SecondVC.m, overwrite the "viewWillAppear" method as follows:
- (void) viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
self.townLabel.text = self.townText;
}
Then, in the FirstVC.m, overwrite the "prepareForSegue" method:
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
SecondVC *secondVC = segue.destinationViewController;
secondVC.townText = self.townTextView.text; // townTextView is the TextView in screen where user writes the town name.
}
Don't forget to import the SecondVC.h in the FirstVC.m

Easy way:
Use storyboard's IBOutlet feature. One view controller class can hold a reference to another view controller
If the code just reference the other view controller
-(void)clickOK:(UIButton*)
{
NSString* town = self.anotherController;
//do something with town
}
Suggested way:
Follow the model-view-controller design pattern. Treat first view controller as a data provider
Protocal DataProviderDelegate
{
#required
-(NSString*)getTown;
-(NSString*)getState;
}
#implementation
FirstViewController:UIViewController<DataProviderDelegate>
{
}
#declaration
SecondViewController:UIViewController
#property(nonatomic, weak)DataProviderDelegate* dataProvider;
In the segue, assign first view controller to the second view controller as a delegate

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.

How to set imageView image on prepareForSegue iOS?

I tried to push to a ViewController using prepareForSegue. When I'm pushing, I want to set an image on ImageView in pushed view controller. Here what I tried,
ViewController
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
UIButton *btn = sender;
if (btn.tag == 50) {
if (jpegData) {
[self saveTempImage:jpegData];
}
if ([segue.identifier isEqualToString:#"HomeView"]) {
HomeViewController *vc = [segue destinationViewController];
vc.backImageView.image = capturedImage;
vc.isBackImage = true;
}
}
}
I have an ImageView in HomeViewController. I tried to set it's image using this vc.backImageView.image = capturedImage;. capturedImage is not null. But the image is not set in ImageView.
How can I fix this?
Thanks in Advance!
Your outlates are not yet set there, I believe backImageView is null at this point. Have backImage property and when backImageView is ready (added to view hierarchy, viewDidLoad is good place for that) then set its image property.
1) You should make the backImageView property (and all the other outlets of HomeViewController) private, because for this view, HomeViewController is exclusively responsible and no other class should be able to manipulate this view. This is current established convention in iOS development. You can do this by adding class extension above the #implementation keyword in HomeViewController .m file.
#interface HomeViewControler ()
#property (nonatomic, strong) IBOutlet UIImageView *backImageView;
//...other private properties ...
#end
#implementation MyViewControler
Right after that, you need to move view outlet properties from the .h interface file to the .m interface extension to have the declared privately.
2) You should create a private property called capturedImage in the extension too.
#interface HomeViewControler ()
#property (nonatomic, strong) IBOutlet UIImageView *backImageView;
#property (nonatomic, strong) UIImage *capturedImage;
#end
3) Declare a public method in h. file called configureWithImage
-(void)configureWithImage:(UIImage *)paramImage;
and implement it i m. file like this
-(void)configureWithImage:(UIImage *)paramImage
{
self.capturedImage = paramImage;
}
4) Next you need to make sure the passed image is used in the imageview, for that HomeViewController's viewDidLoad makes a lot of sense.
-(void)viewDidLoad
{
[super viewDidLoad];
self.backImageView.image = self.capturedImage;
//...other code...
}
5) Last step, in prepareForSegue you configure your view controller with the image
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
UIButton *btn = sender;
if (btn.tag == 50)
{
//...other code...
if ([segue.identifier isEqualToString:#"HomeView"])
{
HomeViewController *vc = [segue destinationViewController];
[vc configureWithImage:capturedImage];
//...other code...
}
}
The "morale of the story" is that by having a proper public interface that is the sole entry point for configuration (the config method) you decouple the two entities. It means the source view controller merely passes the image without having to know ANYTHING about what happens in the destination VC. The image is then processed by the responsible destination view controller.
Should you change your mind and do some layout/view content changes in the HomeViewController (possible filter and process the image for visual effects) later in time, the source view controller will not be affected at all because wheat happens in HomeViewController is nobody else's concern, and you will keep the public configuration method intact. That means the change will not require to maintain code in prepareForSegue, only in the destination VC.

pass back data without protcols

i need to pass some data to previous view controller, what is problem with my codes? in this code "contactViewController" is my first view controller and "groupViewController" is my second view controller
ContactEditVC.h (firstViewController)
#import "GroupEditTVC.h"
#interface ContactEditVC : UIViewController <SecondViewControllerDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate> {
UIImageView * imageView;
UIButton * choosePhotoBtn;
UIButton * takePhotoBtn;
UIButton * btnGroup;
}
#property (nonatomic, strong) NSString *groupName;
ContactEditVC.m (firstViewController)
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([[segue identifier] isEqualToString:#"selectGroup"]){
//get selected contact
//pass selected contact to MyContactAppViewController for editing
GroupEditTVC *destViewcontroller=segue.destinationViewController;
destViewcontroller.delegate=self;
}
}
-(void)viewWillAppear:(BOOL)animated
{
self.txtFname.text=groupName;
}
- (void)dataFromController:(NSString *)data
{
groupName=data;
}
And in my second vie controller:
#protocol SecondViewControllerDelegate <NSObject>
- (void)dataFromController:(NSString *)data;
#end
#interface GroupEditTVC : UITableViewController <UIAlertViewDelegate>
#property (retain) id <SecondViewControllerDelegate> delegate;
#end
GroupEditTVC.m (secendViewController)
#import "ContactEditVC.h"
#interface GroupEditTVC ()
#end
#synthesize delegate;
- (IBAction)donePressed:(id)sender {
[[self delegate]dataFromController:#"blabla"];
[self dismissViewControllerAnimated:YES completion:nil];
}
Is there any another way to pass back data?
You should try to follow Model View Controller. In my applications I usually pass around a reference to a Model class that holds a lot of data that I want to share and change. If you pass the model reference to the GroupEditTVC and you change the data in that screen, that changed data is available to the "root" view controller that also has a reference to the same data. The only thing that is needed is that that "root" view refreshes it's views with the new data.
So you don't need to pass anything back, you just update the Model class that the edit view and the main view both have a reference to.
Example
The idea is to get around passing strings and other "loosely coupled" data around and just act on one solid data object that holds all related data. This is also easier when you start working with AFNetworking / Mantle / etcetera. You just save the whole class of data and you don't have to worry about each little piece of data.
So all references to loose strings should be replaced to strings inside this object.
-(void)viewWillAppear:(BOOL)animated {
self.txtFname.text = self.contact.name;
}
Data class
// class that holds the data
#interface Contact : NSObject // Nothing special, just an object
#property NSInteger contactId;
#property NSString *name;
// You can add basically any data here
#end
Segue
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if([[segue identifier] isEqualToString:#"selectGroup"]){
//pass selected contact to MyContactAppViewController for editing
GroupEditTVC *destViewcontroller=segue.destinationViewController;
destViewcontroller.contact = self.contact; // Adds reference to the same class
}
}
Done editing
- (IBAction)donePressed:(id)sender {
self.contact.name = self.name.text; // get new name from text box
[self dismissViewControllerAnimated:YES completion:nil];
}

IOS Delegation with custom class objects; pass object from modal view to parent view

First, I apologize for asking another delegation question. I've read many and can't find any that deal with passing something complex...
Here's what I am doing...
In my app, I have a ViewController: CollisionViewController where I want to let the user select two vehicles that are involved in a collision. All the vehicles are stored using CoreData and presented modally in SelectVehicleViewController. SelectVehicleViewController lists all the vehicles using a UICollectionView. In CollisionViewController, I have properties for Vehicle1 and Vehicle2 which are of a custom class that describes the properties of a vehicle.
In the CollisionViewController, I am using a UIButton to let the user first select Vehicle1, then Vehicle2 from SelectVehicleViewController presented modally.
I am using seques to determine which button was pressed before presenting the modal SelectVehicleViewController.
How do I setup a protocol that allows the user to pass the selected vehicle from the modal view to the correct vehicle object in the CollisionViewController?
collisionViewController should conform your protocol.
collisionViewController.h
#import "SelectVehicleViewController.h"
#interface ContactViewController : UIViewController <SelectVehicleDelegate>
collisionViewController.m
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqual:#"segueName"]) {
SelectVehicleViewController* VC = segue.destinationViewController;
VC.delegate = self;
//here you should probably send if you will select the vehicule 1 or 2
}
}
- (void)ViewController:(UIViewController *)sender
didUpdateData:(NSString *)value {
//do what you need with new data
//here you should have info if it is for vehicle 1 or 2
}
SelectVehicleViewController.h
#protocol SelectVehicleDelegate;
#interface SelectVehicleViewController : UIViewController
#property (nonatomic, assign) id <SelectVehicleDelegate> delegate;
#end
#protocol SelectVehicleDelegate <NSObject>
- (void)ViewController:(UIViewController *)sender
didUpdateData:(NSString *)value; //adapte according to what you should send back
#end
SelectVehicleViewController.m
//somewhere in a button click or....
[self.delegate ViewController:self didUpdateData:#"new value"];
//in this function you should have info if it is for vehicle 1 or 2

Sending data from a UIlabel from one view controller to another

I have two view controllers
DetailViewController
BlogViewController
I have a 'push' set-up on the storyboard with the identifier 'ShowBlog'
i need to send the title of the blog from the UILabel below on the DetailViewController:
#property (strong, nonatomic) IBOutlet UILabel *TitleLabel;
to a UILabel on the BlogViewController called BlogTitleLabel:
#property (strong, nonatomic) IBOutlet UILabel *BlogTitleLabel;
i know i need to use:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"ShowBlog"]) {
// Im struggling with the code
}
}
But im struggling with the code to go in it
Use NSUserDefaults the code goes something like this:
Store the title:
[[NSUserDefaults standardUserDefaults] setObject:label.title forKey:#"nameForStoredVariableHere"];
[[NSUserDefaults standardUserDefaults] synchronize];
Retrieve the stored title:
NSString *storedTitle = [[NSUserDefaults standardUserDefaults] objectForKey:#"nameForStoredVariableHere"];
After that you're free to use the title as you please
prepareForSegue is called before destination VC's viewDidLoad so don't try to access any view object of destination view controller in prepareForSegue. Its better you create a string property in destination and set that in prepareForSegue method. In destination viewController's viewDidLoad set it to label.
You should not try to send data from label to label. Labels are view objects. They display information and collect input from the user. They do not store information.
Also, you should never, ever try to manipulate another view controller's views directly. That violates the other view controller's encapsulation.
Both view controllers should have NSString properties for this. Let's call it blogTitle on both VCs.
Your DetailViewController should set it's blogTitle somewhere during it's setup, and then in viewWillAppear:animated, display that value to it's titleLabel outlet:
- (void) viewWillAppear: animated;
{
[super viewWillAppear: animated];
self.titleLabel.text = self.blogTitle;
//your other code here
}
Then, in your prepareForSegue:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"ShowBlog"])
{
BlogViewController *theBlogController = [segue destinationViewController];
theBlogController.blogTitle = self.blogTitle; //Pass the blog title to the other VC
}
}
And then in the BlogViewController's viewWillAppear, copy the blogTitle to it's title label:
- (void) viewWillAppear: animated;
{
[super viewWillAppear: animated];
self.titleLabel.text = self.blogTitle;
//your other code here
}
Note that Cocoa/iOS programming has strong naming conventions that you should follow. Only filenames and class names should start with a capital letter. Method names, instance variable names, and property names should start with a lower-case letter. So your TitleLabel should be titleLabel, and BlogTitleLabel should be blogTitleLabel.

Resources