1

(I know this has been asked before, unfortunately none of the related StackOverflow answers I've looked through and tried out while trying to figure this problem out have worked for me. Any help would be much appreciated.)

I'm building a simple news app. The opening screen grabs the latest news entry using Parse's API.

First screen

And when you tap the menu button, you get a UITableView of past news days:

Sliding menu

I want to be able to pass the id from the selected Parse table cell back to the main view.

I'm using ECSlidingViewController for the sliding menu and a Storyboard for the various screens:

The Storyboard

But because of the way I'm using ECSlidingViewController, I can't figure out how to pass data via segues like I otherwise would be able to, so I'm trying to just pass it via the view controllers with a custom init.

Here's my MainViewController.h code:

@interface MainViewController : UIViewController

@property (nonatomic) NSString *detailId;

- (id)initWithDetailId:(NSString*)theId;

@end

Here's my didSelectRowAtIndexPath code in MenuViewController.m:

MainViewController *mainVC = [[MainViewController alloc] initWithDetailId:@"test"];
[self.navigationController pushViewController:mainVC animated:YES];

Here's MainViewController.m's initWithDetailId:

- (id)initWithDetailId:(NSString*)theId
{
    NSLog(@"initWithDetailId");
    self = [super initWithNibName:nil bundle:nil];
    if (self) {
        detailId = theId;
    }
    return self;
}

And here's MainViewController.m's viewDidLoad:

- (void)viewDidLoad
{
    [super viewDidLoad];

    NSLog(@"detailId equals: %@", self.detailId);
}

But all I get from the NSLog is "detailId equals: (null)". What am I doing wrong here? Thanks!

ahow
  • 57
  • 1
  • 6
  • The best answer for passing data between view controllers is here: http://stackoverflow.com/questions/5210535/passing-data-between-view-controllers The basic idea is that you should create a segue between your prototype cell and the main view controller, use `prepareForSegue` to set `detailId` in the `destinationController` as discussed in that other post, and retire your current `didSelectRowAtIndexPath`. – Rob Feb 10 '13 at 04:11
  • Rob, I'd tried that before, and because of the way I'm trying to structure this app (Main view that shows 1 view by default, and then you access the Menu for the table view), I don't have a Navigation Controller. Do I not need one in order to use segues? If I remember correctly I was getting an error when I tried `prepareForSegue` before, saying I needed a Nav Controller. – ahow Feb 10 '13 at 12:54
  • You may be confusing two completely separate issues. Whether you use segues has nothing to do with whether you use navigation controller. You need navigation controller if you want to use a _push_ segues, though. (You also need nav controller if you use `pushViewController` like your code above!) If you use modal segues, though, no nav controller needed (and, in code, you'd present/dismiss controllers rather than push/pop controllers). I argue for segues because it visually represents the flow of your app, and it simplifies the code. – Rob Feb 10 '13 at 13:55
  • There is another design consideration, whether to use navigation controller or not. Nav controllers offer a nice feature where if you push to a third or fourth controller, you can pop back not just one controller, but multiple levels. You can't do that easily/elegantly if you use modals. So, I often find it useful to use nav controllers even if I don't want the nav bar visible. Thus, I embed my first scene in a nav controller, but then select that nav controller and uncheck "shows navigation bar" in the attributes inspector. No nav bar visible, but all the benefits of push segues. – Rob Feb 10 '13 at 14:01
  • Hi Rob, thanks a ton for your help so far, I realized this morning I might be having problems for another reason as well. In the `didSelectRowAtIndexPath` function, above where I'm creating `*mainVC`, the ECSlidingViewController requires this `UIViewController *newTopViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"Main"];`. Even though, through NSLog, I'm seeing that `initWithDetailId` is being called, is it being overwritten by this `*newTopViewController`? – ahow Feb 10 '13 at 14:21
  • 1
    See my discussion with Ravindra, below. You could get rid of your `initWithDetailId` method altogether and use the technique in the latter half of Ravindra's answer. I still think that it's more elegant to use segues (add segue from cell prototype to the next scene, eliminate the `didSelectRowAtIndexPath` method, set `detailID` in `prepareForSegue`), but make sure you can get the manual creation of the destination via `instantiateViewControllerWithIdentifier`, like Ravendra suggests, first. – Rob Feb 10 '13 at 14:25
  • 1
    Finally got it working! Thanks a ton, guys. It was a combination of me not needing that initWithDetailId, like you said, and me having that extra UIViewController from the ECSlidingViewController. This code works great: `MainViewController *newTopViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"Main"]; newTopViewController.detailId = @"test";`. And, Rob, your insights have helped me understand more about how best to structure an iOS app, so thanks again. – ahow Feb 10 '13 at 14:52
  • This isn't working for me. It can't seems to find detailId in MainViewController. I imported MainViewController.h, I have the property @property(nonatomic) NSString *detailId; in MainViewController, but the above code is telling me "Property detailId not found in object of type *MainViewController" – Marcel Marino Jul 26 '13 at 18:04
  • Nevermind,I fixed that problem. But now while the code is running fine, detailId just isn't getting populated with the data I assign it. I mean, it gets assigned in the menu controller, but in MainControllerView the variable is empty. – Marcel Marino Jul 26 '13 at 18:56

1 Answers1

0

you have forgot to put self. in front of detailId = theId;

self.detailId = theId;

that is

- (id)initWithDetailId:(NSString*)theId
{
    NSLog(@"initWithDetailId");
    self = [super initWithNibName:nil bundle:nil];
    if (self) {
    self.detailId = theId;
    }
    return self;
}

there is one another method of doing this:

MainViewController *mainVC = [self.storyBoard instantiateViewControllerWithIdentifier:@"yourIdentifier"];
mainVc.detailId=@"test";
[self.navigationController pushViewController:mainVC animated:YES];
Ravindra Bagale
  • 17,226
  • 9
  • 43
  • 70
  • Unfortunately, adding self. to detailId doesn't help. I'd already tried it both ways before. (And I'd seen in previous questions on SO that it's actually considered better syntax to not use self. in an init?) – ahow Feb 10 '13 at 12:50
  • @RavindraBagale +1 for suggesting `instantiateViewControllerWithIdentifier`. -1 for suggesting using accessor methods in `initWithDetailId` method (see [Don’t Use Accessor Methods in Initializer Methods](https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmPractical.html#//apple_ref/doc/uid/TP40004447-SW6)). If you edit your answer to get rid of this suggestion to use `self.detailID` in `initWithDetailId`, I'd be happy to up-vote your answer. – Rob Feb 10 '13 at 15:06