Passing parameters from one View Controller to another in Swift - ios

I am new to Swift. I just want to pass an indexPath.row value from a UITableViewController to another UIViewController. I have done this using Objective-C but I don't know how to do this using Swift. I have tried many tutorials but I am not getting proper result. I am using code for navigation (not storyboard).
Can anyone please help me. Thanks in advance.

You can use prepareForSegue:sender: for this.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (!self.selectedIndexPath) {
self.selectedIndexPath = indexPath;
[self performSegueWithIdentifier:#"kYourSegueName" sender:nil];
}
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if([segue.identifier isEqualToString:"kYourSegueName"]) {
ViewController *viewController = (ViewController *)segue.destinationViewController;
viewController.selectedRow = self.selectedIndexPath.row;
self.selectedIndexPath = nil;
}
}

Related

Redirection for detailsVC is not working on click of UITableView's Cell in Xcode 7

I'm trying to make a simple iOS app by following this (https://www.appcoda.com/use-storyboards-to-build-navigation-controller-and-table-view/) tutorial but when I try to click on the listed items, I don't get redirected to the detail view and just stay on the same page. I'm fairly new to using both Xcode (I'm using Xcode 7) and objective-C so I have no idea what I'm doing. Any kind of help will be very appreciable.
In your case the storyboard ID is RecipeBookViewController
You have to set Storyboard ID for that View controller as explained below.
GO In Xcode utilities pan click on Identity Inspector and set
Storyboard ID = RecipeBookViewController
For more clarification see the Image, and add RecipeBookViewController against Storyboard ID
Follow this code:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
[self performSegueWithIdentifier:#"Your Segue Name" sender:self];
}
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.
if ([segue.identifier isEqualToString:#"Your Segue Name"]) {
DetailViewController *vc= (DetailViewController *)segue.destinationViewController;
NSIndexPath *indexPath = [tableview indexPathForSelectedRow];
vc.(DetailViewController Object)= [(Your tableView Array name) objectAtIndex:indexPath.row];
}
}
In appCoda, they used segue to push so you might be not added this code in your project,
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"segue_Key"]) {
DetailViewController *nextVC = [segue destinationViewController];
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self performSegueWithIdentifier:#"segue_Key" sender:self];
}
If you facing issue in segue then remove the segue connection from storyboard and use below code ,
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
DetailViewController *obj = (DetailViewController *) [self.storyboard instantiateViewControllerWithIdentifier:#"DetailViewController"]; // Identifier must match with the storyboard VC ID, else project git crashed.
[self.navigationController pushViewController:obj animated:YES];
}
If you already done this, then let me know.
If you don't want to use a segue you should create your destination controller by code:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
destinationcontroller *loading = (destinationcontroller *)[self.storyboard instantiateViewControllerWithIdentifier:#"destinationcontroller"];
[self.navigationController pushViewController:loading animated:YES];
}

How make segue called after another method [duplicate]

This question already has answers here:
How to get indexpath in prepareForSegue
(4 answers)
Closed 6 years ago.
I have a TableViewCell with CutomCells,that includes images view, when user selects some row, the image that is in this row should be shown in another viewController.
Connection among these Controllers is done through segue, where I tries to set the image.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"ImageVC"])
{
ImageViewController * ivc = segue.destinationViewController;
ivc.myTemporaryImage = [self.dataDictionary objectForKey:self.names[self.selectedCell]];
}
}
to define which one row was selected I use TableViewDelegates method:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
self.selectedCell = indexPath.row;
[self.dataDictionary objectForKey:self.names[indexPath.row]];
}
The issue here that image is not reflected, cause firstly fires method: prepareForSegue, and only after that - didSelectRowAtIndexPath. But I need to change this order. Could you advice how to do this?
Also I tried to create ImageViewController programmatically, without using segue, directly in method didSelectRowAtIndexPath, but in this image is not shown in this case.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.dataDictionary objectForKey:self.names[indexPath.row]];
ImageViewController * ivc = [[ImageViewController alloc]init];
ivc.myTemporaryImage = [self.savedImages objectForKey:self.names[indexPath.row]];
[self.navigationController pushViewController:ivc animated:YES];
}
Could you please how to manage this issue?
You have to remove the direct reference to your segue in your cell, then, in your tableView delegate call it programmatically:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
self.selectedCell = indexPath.row;
[self performSegueWithIdentifier:#"ImageVC", sender: [self.savedImages objectForKey:self.names[indexPath.row]]]
}
Then in prepareForSegue:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"ImageVC"])
{
ImageViewController * ivc = segue.destinationViewController;
ivc.myTemporaryImage = sender;
}
}
I think you can save the indexPath at the willSelectRowAtIndexPath method.

Is a prepareForSegue notify a view controller when a segue is about to preform to another view controller?

Up until now I have used prepareForSegue method to notify a view controller he is about to review a segue from a different view controller, but if i'm the vc that sending the segue, will my prepareForSegue (in he same class of the segue sender) will check if there is a code to preform before he fires the segue?
I'm asking because I got a solution here to preform a simple segue just to go from stable view row which represent notes to the creation page of the note for editing...very simple, but from some reason it's not presenting my note in the creation page, only takes me to a new clean creation page..
So I though maybe it's because the prepareForSegue method..here you can see the question to give you more details How to to create a segue to push back to editing mode from a table view?
Would really appreciate to get your help on this.
This are the 2 methods I added to my NotesList table view controller:
#pragma mark - delegate
- (void) tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self performSegueWithIdentifier:#"noteSegue" sender:nil];
}
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"noteSegue"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
NMNote *note = [self.notes objectAtIndex:indexPath.row];
NMCreateNotesViewController *destination = [segue destinationViewController];
destination.textField.text = note.content;
}
}
And I made sure the segue identifier in the storyboard is named noteSegue. So why its note working...Im getting a new TextView instead of populating it with the note content :/
This is the error i'm getting:
Thanks!
The prepareForSegue: method is called on the current VC not the destination. UIViewController Class Reference. You can use the method to obtain a reference to the destination VC and set variables/call methods on it before the segue is performed.
Calling the segue like this:
[self performSegueWithIdentifier:#"NAMEOFSEGUE" sender:nil];
You can then prepare the destination VC like this:
#import "NMCreateNotesViewController.h"
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"NAMEOFSEGUE"]) {
NMCreateNotesViewController *destination = [segue destinationViewController];
[destination createNote]; /* or something similar */
}
}
EDIT:
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NMNote *note = [self.notes objectAtIndex:indexPath.row];
[self performSegueWithIdentifier:#"noteSegue" sender:note];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"NAMEOFSEGUE"]) {
NMCreateNotesViewController *destination = [segue destinationViewController];
NMnote *note = (NMNote*) sender;
destination.textField.text = note.content;
}
}
To check if there is a code to preform before the segue you can use solution below:
if ([segue.destinationViewController isKindOfClass:[UIViewController class]]) {
UIViewController *nextVC = segue.destinationViewController;
if(nextVC respondsToSelector:#selector(yourMethod)){
[nextVC yourMethod];
}
}
You can check if you are sure to perform the specific segue by implementing this method
- (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender
If you have your note presenting code in viewDidLoad, try moving that to viewDidAppear (in your note editing VC). There used to be an issue when presenting from a TableView row where the segue would fire after VDL was executed.

Data is not transferred to next view Controller

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog((#"This is didSelectRowAtIndexPAth"));
DetailViewController *detailViewController = [[DetailViewController alloc] init];
detailViewController.myDictionary = [self.placeArray objectAtIndex:[indexPath row]];
/* The below NSlog is showing the content , its not null still in next viewcontroller same variable showing null content*/
NSLog(#"My Dictionary: This is a MasterView%#",detailViewController.myDictionary);
[self performSegueWithIdentifier:#"showDetail" sender:self];
}
It is because the presented instance of your DetailViewController is different than the instance you are creating manually. You should either present that new ViewController yourself (modally or by push), or implement the prepareForSegue method and set the dictionary there.
Edit:
The 2 solutions:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
DetailViewController *detailViewController = [[DetailViewController alloc] init];
detailViewController.myDictionary = [self.placeArray objectAtIndex:[indexPath row]];
// If it is a modal
[self presentViewController:detailViewController animated:YES];
}
OR
#implementation MyClass {
NSIndexPath *selectedCellIndexPath;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog((#"This is didSelectRowAtIndexPAth"));
selectedCellIndexPath = indexPath;
[self performSegueWithIdentifier:#"showDetail" sender:self];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"showDetail"]) {
DetailViewController *detailViewController = (DetailViewController *)segue.destinationViewController;
detailViewController.myDictionary = [self.placeArray objectAtIndex:selectedCellIndexPath.row];
}
}
try this
Decalre one NSInteger varable Globaly assign that varble to indexpath.row
#interface DashbordViewController ()
{
NSInteger SelectedRownum;
}
#end
#implementation DashbordViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
SelectedRownum=indexPath.row
[self performSegueWithIdentifier:#"showDetail" sender:self];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"showDetail"])
{
NSLog((#"This is didSelectRowAtIndexPAth%#",SelectedRownum));
DetailViewController *detailViewController = [segue destinationViewController];
detailViewController.myDictionary = [self.placeArray objectAtIndex:SelectedRownum];
}
}
In DetailViewController check if the myDictionary is a property declared as weak or strong..
try this . . .
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog((#"This is didSelectRowAtIndexPAth"));
UIStoryboard *mystoryboard = [UIStoryboard storyboardWithName:#"myStoryBoardName" bundle:nil];
self.detailsViewController = [mystoryboard instantiateViewControllerWithIdentifier:#"detailviewcontroller"]
/* The below NSlog is showing the content , its not null still in next viewcontroller same variable showing null content*/
NSLog(#"My Dictionary: This is a MasterView%#",detailViewController.myDictionary);
[self performSegueWithIdentifier:#"showDetail" sender:self];
}
you have to set identifier of your detailViewController in storyBoard .
You need to assign the dictionary in prepareForSegue: method.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
DetailViewController *viewController = = (DetailViewController *)[segue destinationViewController];
detailViewController.myDictionary = //YOUR Dictionary here;
}
This way the same dictionary can be obtained in viewDidLoad: of DetailViewController.
Note: Make sure you allocate the dictionary.
Hope it helps.
Since I can't see implementation of your controller (being subclass of UIViewController or not), I cannot say a lot, but keep in mind that initWithNibName:bundle: is the designated initializer for UIViewController and not init.
So, this is the first problem. In any case, check the instance before setting a property. It is very likely that instance is nil.
EDIT:
It is also very likely, they you are instantiating new View Controller from existing. In this case, you can add new view controller as child controller or present new controller from existing. In both cases properties of existing are reachable from new through properties: parentViewController and presentingViewController, which makes the story opposite: you take property value from existing controller into new controller.
You are creating new view controller in didSelectRowAtIndexPath, and at the end you are calling prepareForSegue method... which will create new Instance, So you have to set your data which you want to send in new view controller in prepareForSegue method like this.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
//
if ([[segue identifier] isEqualToString:#"name_of_ur_segue"])
{
// Get reference to the destination view controller
DetailViewController *detailViewController = [segue destinationViewController];
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
// Pass any data here ...
detailViewController.myDictionary = [self.placeArray objectAtIndex:[indexPath row]];
}
}
Edit:
As you are accessing data in ViewDidLoad method and in iOS 7 data passed like this is not accessible in ViewDidLoad method. As view controller presentation logic is bit changed now. Now we can pass data in initMethod if we want to access this in viewDidLoad.
Or access this in viewWillAppear or viewDidApepar.
If you want to call this code only once in viewDidAppear or ViewWillApepar just set a boolean flag, which can tell if you want to access this or not.

Pushing a view in Storyboard

I am trying to use Table Views and navigation controllers. This is the code I would use if I was using NIB files. This piece of code would work fine if I was using NIB files, but I decided to try storyboard -
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (_webViewController == nil) {
self.webViewController = [[[WebViewController alloc] initWithNibName:#"WebViewController" bundle:[NSBundle mainBundle]] autorelease];
}
RSSEntry *entry = [_allEntries objectAtIndex:indexPath.row];
_webViewController.entry = entry;
[self.navigationController pushViewController:_webViewController animated:YES];
}
I have created another scene in storyboard and have everything set up out there. When a user clicks a cell in this Table View they will be taken to that scene. This is what I wrote for the code but it is not right and I'm hopelessly stuck :( -
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"articleView"]){
UINavigationController *navigationController = segue.destinationViewController;
WebViewController *controller = (WebViewController *)navigationController.topViewController;
controller.webView = self;
}
Answer - Answers 2 and 3 are both right
I had a very similar problem 2 days ago, with the user selecting the disclosure accessory on a row and wanting to invoke a segue. What worked for me:
In storyboard, create segue "articleView" from the entire tableView controller (not the cell) to the next viewController.
Add the following method to your tableViewController:
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath {
[self performSegueWithIdentifier:#"articleView" sender:[self.tableView cellForRowAtIndexPath:indexPath]];
}
Just for you I also tested with tableView:didSelectRowAtIndexPath: and it works.
Enjoy,
Damien
If your table view is already embedded in a navigation controller (looks that way, from your first code snippet) then the destination view controller of your segue will be a WebViewController, not a navigation controller.
You can therefore have your prepareForSegue method pass the item directly across :
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"articleView"])
{
WebViewController *controller = (WebViewController *)segue.destinationViewController;
RSSEntry *entry = [_allEntries objectAtIndex:[self.tableView indexPathForSelectedRow].row];
controller.entry = entry;
}
}
You may find this excellent two-part tutorial helpful
http://www.raywenderlich.com/5138/beginning-storyboards-in-ios-5-part-1

Resources