Question

I've basically got a Master-Detail app that utilizes RestKit to pull data from a remote server.

The DetailViewController acts as a data source for a PageViewController that has three viewControllers. My question only deals with two of those so I will focus on that. I'll call the two important viewControllers: FirstViewController and SecondViewController.

FirstViewController displays the detail content of the item selected in the master view, basically an image and some text. Scrolling to the SecondViewController displays a UITableView that contains items related to the content in the main view. See this link How to implement UIPageViewController that utilizes multiple ViewControllers for an image of a similar storyboard to the app.

To clarify a little more imagine a recipe app in which you choose a recipe to view in the master scene. The detail scene displays the recipe selected. Scrolling to the next page displays a table with recipes related to the one chosen.

With the background established here is my question:

I am trying to set things up so that a user could select a cell in the tableview and the DetailViewController would reload with the data from the selected cell. For example the user sees a related recipe they are interested in, selects the cell, and the view reloads to the main page in the PageViewController with the data from the selected cell.

I felt the easiest way of doing this might just be to pass some needed variables into the DetailViewController and call viewDidLoad like so.

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    //Grab index object at index path
    NSManagedObject *object = [[self fetchedResultsController] objectAtIndexPath:indexPath];
    //Initialize DVC class to utilize variables and methods
    DetailViewController *vc = detailViewControllerId;
    vc.articleId = [object valueForKey:@"articleId"];
    vc.imageUrl = [object valueForKey:@"image"];
    //Reload the DetailViewController
    [vc viewDidLoad];
}

This works with one exception:

  1. All the variable data is maintained from the from the initial load so when the main screen pops back up I have all the previous data plus the new data.

Calling viewDidLoad has done what I hoped. viewDidLoad starts a sequence of API calls to grab the data from the server and then populates the content viewControllers of the PageViewController. However I need something that will essentially reload it from the beginning blowing out past data.

Does anyone have any better suggestions to accomplish what I am trying to do? Thanks

==========EDIT===============

Here is some more info that may be needed.

Starting from the beginning a user selects a cell in the MasterViewController which triggers a segue to the DetailViewController. I am using prepareForSegue to pass needed data into the DetailViewController.

The DetailViewController acts as the data source for the PageViewController so when viewDidLoad is called in the DetailViewController a series of methods is called populate the data source elements required in the PageViewController. Here is the basics.

DetailViewController.h

@interface DetailViewController : UIViewController<UINavigationControllerDelegate, UIPageViewControllerDataSource>

{

}

@property (strong, nonatomic) UIPageViewController *pageViewController;
@property (strong, nonatomic) NSURL *imageUrl;
@property (strong, nonatomic) NSData *passingPhotoData;  //used to pass to the  pageViewController;
@property (strong, nonatomic) NSAttributedString *passingString; //passes text to pageViewController;
@property (strong, nonatomic) NSArray *vc1;
@property (strong, nonatomic) NSManagedObjectContext *managedObjectContext;
@property (strong, nonatomic) NSString *articleId;

@end

DetailViewController.m

-(void)viewDidLoad
{
    //There is other things in the method but these are the only significant line for the question.
    //The method call below is to start a call to the server to get the information needed about the cell that was selected.
    vc1 = [[NSArray alloc] init];
    [self getDetailInfoFromServer]
}

-(void)getDetailInfoFromServer
{
    //Here I make a call to the server using Restkit… it is not significant for the question so I'll leave it out.
    //The data that is retrieved from this server call is everything that I will use to populate the FirstViewController which is again an image and some text.
    //If the call to the server was successful RestKit maps out the data in Core Data and I move on to the next method.
    [self getInfoRelatedToDetailView]
}

-(void)getInfoRelatedToDetailView
{
    //The data that is retrieved from this server call is everything that I will use to populate the SecondViewController.
    //The SecondViewController is a tableView and the data retrieved will be an array of images and the associated text.
    //If the call to the server was successful Restkit will again map the data into Core Data entities and I move on to the next method.
    [self getTextForFVC]
}

-(void)getTextForFVC
{
    //In this method I fetch the text from Core Data that was received back in getDetailInfoFromServer.
    //It is all HTML which I parse to a string using DTCoreText and finally set passingString equal to the result.  
    //passingString is one of the variables I use to pass needed info to the FirstViewController.
    self.passingString = parsedString

    //At this point I start the setup of the pageViewController, this is just standard stuff that goes with a PageViewController

    FirstViewController *selectedController = [self populateFirstViewController];
    vc1 = @[selectedController];

    // Create page view controller
    self.pageViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"PageViewController"];
    self.pageViewController.dataSource = self;
    [self.pageViewController setViewControllers:vc1  direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];

    //Notice above the call to a method populateFirstViewController That is where I go next.

-(FirstViewController *)populateFirstViewController
{
    //This is a simple method that gets called whenever the PageViewController delegate methods deem it necessary to load the FirstViewController.
    FirstViewController *fvc = [self.storyboard instantiateViewControllerWithIdentifier:@"FirstController"];
    fvc.imageData = self.passingPhotoData; //This variable was set earlier but I left out the code
    fvc.nodeText = self.passingString;
    return nvc;
}

-(SecondViewController *)populateSecondViewController
{
    //This method is like the one above, it is called when the PVC delegate methods deem it necessary to load the page
    SecondViewController *svc =[self.storyboard instantiateViewControllerWithIdentifier:@"SecondController"];
    //Here are some of the variables I pass in
    svc.managedObjectContext = self.managedObjectContext;
    cvc.detailViewControllerId = self;  //This line allows me to call the viewDidLoad method for the DetailViewController from the SecondViewController.

    return cvc;
}

Once all this take place the PageViewController appears with the data received from the server. The FirstViewController handles populating the UIImageView and UITextField. Likewise the SecondViewController handles populating the UITableView.

Now for the meat of the question… A user sees something they are interested in the table and selects it. I use the didSelectRowAtIndexPath to get information I need for the calls to the server and then need the PageViewController to reload. Given that the DetailViewController is the data source for the PVC, I need the data source to refresh/reload. I thought it would be easy to just call viewDidLoad to start the process but I'm not sure it is the appropriate way. What might be the best way to do this?

Sorry for the Novel, just wanted to clarify for those that have put in their input.

Was it helpful?

Solution

The usual way to pass data back to a previous controller is through delegation. You should have a delegate protocol in the controller that shows the related recipes (in your example), and the initial detail controller should set itself as the delegate. When the user selects one of the related items, call the delegate method, which would pass back the data needed to reload the detail controller.

Now to your exceptions,

  1. You get that error because your property declaration is wrong -- it should be,

    @property (strong, nonatomic) DetailViewController *vc;

And in your code you should refer to it with self.vc, not create a local variable (which is what you're doing in the posted code) with the same name as the property,

self.vc = detailViewControllerId;

It's not really clear what you're doing with that line anyway, since you don't say what detailViewControllerId is.

  1. You really shouldn't call viewDidLoad directly. The controller calls that when it loads its view. Since you didn't say how you load the detail controller in the first place, it's hard to say why you get the old data plus the new. What you should do is set the array that you use to populate the table to the values you send back in the the delegate method.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top