I have tried all the ways to pass this data between the view Controllers, both of which are modally represented as page sheet.
in ViewController 1 .h
——————————
#property (strong, nonatomic) NSMutableDictionary * updatableProduct ;
//#property (strong, nonatomic) NSDictionary * updatableProduct ; //tried
in ViewController 1 .m
——————————
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString * cellIdentifier = #"Cell";
TailorOUCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
cell.updateOrder.tag = indexPath.row;
[cell.updateOrder addTarget:self action:#selector(nowUpdateOrder:) forControlEvents:UIControlEventTouchUpInside];
orderToUpdate = [orderQueryResults objectAtIndex:indexPath.row];
return cell;
}
-(void)nowUpdateOrder:(id)sender{
UIButton *senderButton = (UIButton *)sender;
updatableProduct = [orderQueryResults objectAtIndex:(long)senderButton.tag];
[self performSegueWithIdentifier:#"updateOrder" sender:updatableProduct];
//[self performSegueWithIdentifier:#"updateOrder" sender:self]; //tried
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([segue.identifier isEqualToString:#"updateOrder"]) {
OUEditView * ouv = (OUEditView *)segue.destinationViewController;
ouv.orderDetails = updatableProduct;
[segue.destinationViewController setModalPresentationStyle:UIModalPresentationPageSheet];
}
}
in ViewController 2 .h
——————————
#property (strong, nonatomic) NSMutableDictionary * orderDetails ;
in ViewController 2 .m
——————————
#synthesize orderDetails;
But the orderDetails = null in log
Any Help!
You need to add breakpoints or log statements to your code and see what's happening.
Is prepareForSegue being called at all?
Is the IF statement matching the identifier?
Is the value in "updatableProduct" not nil?
Are you checking the value of ouv.orderDetails in viewDidLoad or
viewWillAppear, instead of in the init method? (The init method fires
before prepareForSegue is called.)
Related
I have 2 viewcontrollers (A and B). When i click on selected record in VC A, it will redirect to VC B. In my VC B, i have UICollectionReusableView to display header for details.
May i know how to pass data from VC A to VC B UICollectionReusableView? Attached herewith my code :-
VC A (I able to get value in NSLog here)
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
Merchant_TableViewCell *cell=[tableView cellForRowAtIndexPath:indexPath];
//Link to Shop page
MerchantDetail_ViewController *MerchantDetail_ViewControl = [[MerchantDetail_ViewController alloc] init];
MerchantDetail_HeadView *MerchantDetail_Head = [[MerchantDetail_HeadView alloc] init];
MerchantDetail_Head.strName = cell.nameLabel.text;
NSLog(#"strname - %#",MerchantDetail_Head.strName);
[self.navigationController pushViewController:MerchantDetail_ViewControl animated:YES];
}
In VC B UICollectionReusableView .h file
#interface MerchantDetail_HeadView : UICollectionReusableView
#property (nonatomic, retain) IBOutlet NSString *strName;
#property (nonatomic, retain) IBOutlet NSString *strImage;
In VC B UICollectionReusableView .m file (NSLog here will get null value)
- (void)awakeFromNib {
[super awakeFromNib];
self.headImageButton.clipsToBounds = YES;
self.headImageButton.layer.cornerRadius = 30;
self.nickNameLabel.text = strName;
NSLog(#"Head View - %#",strName);
}
Any idea? Please help thx.
This question already has answers here:
Passing data between view controllers
(45 answers)
Closed 7 years ago.
I have looked all over this website for 3 hours now and i cannot find out how to do this without referencing to manually connecting all of my 106 collection view cells with segues to another ViewController.
I would like to be able to click on my CustomCell (we will call it A) when i click on A i want to open a new viewController with the Page Title being A and the image i have set in the CustomCell to be the Page Logo within a UIImage on the view controller page.
I am aware this has to do with passing information between ViewControllers and i have no idea how to do this. Therefore i am very stuck.
I have only been using Xcode for a month now and i need it for my apprenticeship project so it would be very helpful if someone could help me.
My Current code is as follows, if someone is so kind enough to help please could you comment your code so that i get a further understanding as i don't just want to copy and paste the code and learn nothing from it.
Many thanks in advance.
ViewController.m
#import "GroupsViewController.h"
#import "GroupsHomeViewController.h"
#import "CustomCell.h"
#interface GroupsViewController ()
{
NSArray *arrayOfImages;
NSArray *arrayOfDescriptions;
}
#end
#implementation GroupsViewController
{
NSString *reuseIdentifier;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[[self GroupsCollectionView]setDataSource:self];
[[self GroupsCollectionView]setDelegate:self];
reuseIdentifier= #"SmallIcon";
arrayOfImages = [[NSArray alloc]initWithObjects:#"A.png", nil];
arrayOfDescriptions = [[NSArray alloc]initWithObjects:#"A",nil];
}
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return [arrayOfDescriptions count];
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
CustomCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];
[[cell IconImage]setImage:[UIImage imageNamed:[arrayOfImages objectAtIndex:indexPath.item]]];
[[cell IconLabel]setText:[arrayOfDescriptions objectAtIndex:indexPath.item]];
return cell;
}
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
[self performSegueWithIdentifier:#"customSegue" sender:indexPath];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
NSIndexPath *indexPath = (NSIndexPath *)sender;
UIImage *imageToShow = [UIImage imageNamed:[arrayOfImages objectAtIndex:indexPath.item]];
NSString *titleToShow = [arrayOfDescriptions objectAtIndex:indexPath.item];
GroupsHomeViewController * destination = (GroupsHomeViewController *)segue.destinationViewController;
destination.groupLabel = *titleToShow; //assigning to UILabel form incompatible type NSString
destination.logoImage = *imageToShow; // UIImageView from incompatible type UImage
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
//Dispose of any resources that can be recreated.
}
// Toggle View Button
- (IBAction)cellToggleAction:(id)sender {
if([reuseIdentifier isEqualToString:#"SmallIcon"]){
reuseIdentifier=#"ListView";
[sender setImage:[UIImage imageNamed:#"LargeIcon"]];
}
else if
([reuseIdentifier isEqualToString:#"ListView"]){
reuseIdentifier=#"LargeIcon";
[sender setImage:[UIImage imageNamed:#"SmallIcon"]];
}
else if
([reuseIdentifier isEqualToString:#"LargeIcon"]){
reuseIdentifier=#"SmallIcon";
[sender setImage:[UIImage imageNamed:#"ListView"]];
}
[self.GroupsCollectionView reloadData];
}
//Toggled Cell Sizes
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
CGSize cellSize;
if([reuseIdentifier isEqualToString:#"SmallIcon"])
cellSize = CGSizeMake(100, 130);
else if
([reuseIdentifier isEqualToString:#"ListView"])
cellSize = CGSizeMake(320, 50);
else if
([reuseIdentifier isEqualToString:#"LargeIcon"])
cellSize = CGSizeMake(320, 350);
return cellSize;
}
#end
GroupsHomeViewController.m where the groups view controller pay goes to.
#import "GroupsHomeViewController.h"
#interface GroupsHomeViewController ()
#end
#implementation GroupsHomeViewController
-(void)viewDidLoad{
[super viewDidLoad];
self.groupLabel.text = self.groupLabel; //incompatible pointertypes assigning to NSSstring
self.logoImage.image = self.logoImage; //incompatible pointer types assigning to NSSstring
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
#end
CustomeCell.h
#import <UIKit/UIKit.h>
#interface CustomCell : UICollectionViewCell
#property (weak, nonatomic) IBOutlet UIImageView *IconImage;
#property (weak, nonatomic) IBOutlet UILabel *IconLabel;
#end
Ok. This is a pretty big question. But first of all you would need to make a custom VC subclass for the target of the segue. You should definitely not have 106 different segues. Especially since it sounds like they will all be basically leading to the same place. A View controller that can show an image and a name. setup this new VC in your storyboard and make one segue from the viewController (not the cell) (Drag from the yellow circle ontop of the collection VC) to the new VC. and call it customSegue
SO setup a subclass something like:
#interface SelectedInfoViewController : UIViewController
#property (strong, nonatomic) NSString *selectedInfoName;
#property (strong, nonatomic) UIImage *selectedInfoImage;
#end
#implementation SelectedViewController
-(void)viewDidLoad{
[super viewDidLoad];
self.labelForTitle.text = self.selecteInfoName;
self.imageViewForImage.image = self.selecteInfoImage;
}
#end
Then you would add to your collection view controller.
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
[self performSegueWithIdentifier:#"customSegue" sender:indexPath];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
NSIndexPath *indexPath = (NSIndexPath *)sender;
UIImage *imageToShow = [UIImage imageNamed:[arrayOfImages objectAtIndex:indexPath.item]];
NSString *titleToShow = [arrayOfDescriptions objectAtIndex:indexPath.item]];
SelectedInfoViewController * destination = (SelectedInfoViewController *)segue.destinationViewController;
destination.selectionInfoName = titleToShow;
destination.selectionInfoImage = imageToShow;
}
Hope this makes some sense. Let me know if you need more help.
As per your errors:
destination.groupLabel = *titleToShow; //assigning to UILabel form incompatible type NSString
destination.logoImage = *imageToShow; // UIImageView from incompatible type UImage
self.groupLabel.text = self.groupLabel; //incompatible pointertypes assigning to NSSstring
self.logoImage.image = self.logoImage; //incompatible pointer types assigning to NSSstring
These are two separate things that you are assigning to each other.
So as I highlighted you need to setup:
#interface SelectedInfoViewController : UIViewController
#property (strong, nonatomic) NSString *selectedInfoName;
#property (strong, nonatomic) UIImage *selectedInfoImage;
but also we need:
#property (strong, nonatomic) IBOutlet UILabel *infoLabel;
#property (strong, nonatomic) IBOutlet UIImageView *infoImage;
#end
Soooo. In the segue you should be setting the selectedInfoName, and selectedInfoImage. And then in the viewDidLoad you should be setting the infoLabel.text property to the passed selectedInfoName and the infoImage.image property to the passed selectedInfoImage.
Oh also as I had alluded before you need to link the infoLabel & infoImage to their respective counterparts in the storyboard.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
self.data= [self.nameList objectAtIndex:indexPath.row];
self.data= [self.rollList objectAtIndex:indexPath.row];
[self performSegueWithIdentifier:#"DetailVC" sender:self];
}
I've displayed student's name and roll number in custom cell. Now when i select one row i would like to pass those data to another UIViewController and display in labels. For I've one NSObject type file called 'Name' and i've one variable called 'data' which is of type 'Name'. Now here's my code in didSelectRowAtIndexPath where the nameList is overlapped by rollList which are stored on same variable self.data. if rollList line is removed then it works good. But when I store rollList in self.data it will overlap other.
Where, self.nameList is variable of type NSMutableArray which contains name of student and similarly, self.rollList contains student's roll.
Below is the code to pass data from segue. Here DetailVC is the destinationViewController, vc.data is the variable of type 'Name' and self.data is also the variable of same type.
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([segue.identifier isEqualToString:#"DetailVC"]){
DetailVC *vc = (DetailVC *) segue.destinationViewController;
vc.data = self.data;
}
}
Overlapping is fundamental thing.
In your case your in NSObject type file (Name) you have to add two variable
NSNumber *rollNo;
NSString *name;
After that
-- UPDATE --
#interface TableVC : UIViewController {
Name *data;
}
-(void)viewDidLoad {
data = [[Name alloc] init]
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
self.data.name = [self.nameList objectAtIndex:indexPath.row];
self.data.rollNo = [self.rollList objectAtIndex:indexPath.row];
[self performSegueWithIdentifier:#"DetailVC" sender:self];
}
Then
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([segue.identifier isEqualToString:#"DetailVC"]){
DetailVC *vc = (DetailVC *) segue.destinationViewController;
vc.data = self.data;
}
}
------ Detail VC ---
#property (nonatomic, strong) Name *data;
-(void)viewDidLoad {
self.labelRollNo.text = self.data.rollNo;
self.labelName.text = self.data.name;
}
try this way
#interface ViewController ()
{
NSString *name;
NSString *roll;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
name= [self.nameList objectAtIndex:indexPath.row];
roll= [self.rollList objectAtIndex:indexPath.row];
[self performSegueWithIdentifier:#"DetailVC" sender:self];
}
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([segue.identifier isEqualToString:#"DetailVC"]){
DetailVC *vc = (DetailVC *) segue.destinationViewController;
vc.name = name;
vc.roll = roll;
}
}
you create two NSString name and roll properties in your DetailVC
DetailVC.h
#property (strong, nonatomic) NSString *name;
#property (strong, nonatomic) NSString *roll;
I'm trying to push data to a detail view. I'm able to push to the new view but the object equals null.
ProfileDetailView.h
#property (nonatomic, strong) PFObject *user;
#property (weak, nonatomic) IBOutlet UILabel *username;
#property (weak, nonatomic) IBOutlet UILabel *bio;
#property (weak, nonatomic) IBOutlet UILabel *name;
TableViewController.m
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
PFObject *object = [self.objects objectAtIndex:indexPath.row];
ProfileDetialView *controller = [[ProfileDetialView alloc]initWithNibName:#"ProfileDetialView" bundle:Nil];
controller.user = object;
//NSLog(#"%#",controller.user);
[self performSegueWithIdentifier: #"ShowDetails" sender: self];
}
I've tried doing this multiple ways but ether it won't push to new view or it wont pass the object to the new view. It's probably something stupid as usually but any suggestions would be appreciated!
You should use prepareForSegue.
Assume ShowDetails segue goes to ProfileDetailView (and it is a controller) (am I right?).
you should add into TableViewController
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"ShowDetails"]) {
ProfileDetailView *detailController = segue.destinationViewController;
detailController.user = (PFObject *) sender;
}
}
and change :
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
PFObject *userObject = [self.objects objectAtIndex:indexPath.row];
[self performSegueWithIdentifier: #"ShowDetails" sender: userObject];
}
You code doesn't work, because you instantiate NEW detail controller, add data to it, but segue opens ANOTHER instance of detail controller (where you have no data).
try into prepareForSegue method, and in the performSegue in sender object
[self performSegueWithIdentifier: #"ShowDetails" sender: object];
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"ShowDetails"]) {
ProfileDetialView *controller = (ProfileDetialView *)segue.destinationViewController;
PFObject *object = (PFObject *)sender;
controller.user = object;
}
}
hope it works for you
My app have UITableViewController and DetailViewController.
UITableViewController with multi cell selection and Detail accessory button.
If the user select multiple cell and tap on TOTAL Button Alert message show the total of courses price.
And if user tap on Detail accessory button it Segue to DetailViewController.
OK now my problem is how could I do that with my code:
UITableViewController.m
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
NSManagedObject *object = [self.fetchedResultsController objectAtIndexPath:indexPath];
cell.textLabel.text = [[object valueForKey:#"courseCode"] description];
cell.detailTextLabel.text = [[object valueForKey:#"courseName"] description];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"showDetail"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
NSManagedObject *object = [[self fetchedResultsController] objectAtIndexPath:indexPath];
[[segue destinationViewController] setDetailItem:object];
}
}
-(void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath{
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSManagedObject *object = [self.fetchedResultsController objectAtIndexPath:indexPath];
if ([[[object valueForKey:#"creditHours"] description]isEqualToString: #""]) {
}
//some thing doing if the user deselect the cell..
}
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSManagedObject *object = [self.fetchedResultsController objectAtIndexPath:indexPath];
if ([[[object valueForKey:#"creditHours"] description]isEqualToString: #""]) {
}
//some thing doing if the user deselect the cell..
}
- (IBAction)doneButton:(id)sender {
given the total...
}
DetailViewController.h
#property (strong, nonatomic) id detailItem;
#property (weak, nonatomic) IBOutlet UITextField *courseCodeLabel;
#property (weak, nonatomic) IBOutlet UITextField *courseNameLabel;
#property (weak, nonatomic) IBOutlet UITextField *creditHoursLabel;
#property (weak, nonatomic) IBOutlet UITextField *preRequisitesLabel;
#property (weak, nonatomic) IBOutlet UITextField *coursePriceLabel;
#property (weak, nonatomic) IBOutlet UITextField *courseEPPLabel;
#property (weak, nonatomic) IBOutlet UITextView *courseDetailLabel;
DetailViewController.m
#interface DetailViewController ()
- (void)configureView;
#end
#implementation DetailViewController
#synthesize detailItem = _detailItem;
#synthesize courseCodeLabel = _courseCodeLabel;
#synthesize courseNameLabel = _courseNameLabel;
#synthesize creditHoursLabel = _creditHoursLabel;
#synthesize preRequisitesLabel = _preRequisitesLabel;
#synthesize coursePriceLabel = _coursePriceLabel;
#synthesize courseEPPLabel = _courseEPPLabel;
#synthesize courseDetailLabel = _courseDetailLabel;
#pragma mark - Managing the detail item
- (void)setDetailItem:(id)newDetailItem
{
[self configureView];
if (_detailItem != newDetailItem) {
_detailItem = newDetailItem;
// Update the view.
[self configureView];
}
}
- (void)configureView
{
// Update the user interface for the detail item.
if (self.detailItem) {
self.courseCodeLabel.text = [[self.detailItem valueForKey:#"courseCode"] description];
self.courseNameLabel.text = [[self.detailItem valueForKey:#"courseName"] description];
self.creditHoursLabel.text = [[self.detailItem valueForKey:#"creditHours"] description];
self.preRequisitesLabel.text = [[self.detailItem valueForKey:#"preRequisites"] description];
self.coursePriceLabel.text = [[self.detailItem valueForKey:#"coursePrice"] description];
self.courseEPPLabel.text = [[self.detailItem valueForKey:#"courseEPP"] description];
self.courseDetailLabel.text = [[self.detailItem valueForKey:#"courseDetails"] description];
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self configureView];
}
Notice that the segue working good in the normal way.
I think currently your segue links a tableview cell (that prototype) with your detail controller. You can try instead link the tableview controller itself (i.e. the entire thing) with your detail controller. (just ctrl drag from the bottom of your tableview controller to do that)
Then you handle your -prepareForSegue method as usual, but you will need to call -performSegue to actually trigger the segue. Tapping on the cell will have no effect. So in your -tableView:tableViewaccessory.... method you can call performSegue to do your navigation, and handle your didSelectRow.. method as you wish.