Search code examples
iosobjective-cuiviewcontrolleruicollectionviewpresentviewcontroller

Why do my UICollectionView support methods only invoke when my ViewController is set as Initial View Controller?


I have a very simple ViewController called CViewController with a basic UICollectionView inside of it.

When I make CViewController the Initial View Controller, everything works fine and my UICollectionView populates itself as planned. No problems there in the slightest.

When I try to modally present CViewController from any other ViewController, the UICollectionViewDataSource, UICollectionViewDelegate, and the UICollectionViewDelegateFlow protocols never invoke.

I simply get the classic "black hole" that appears when a UICollectionView is never populated with data. None of the expected delegate methods are being called according to my log, yet the CViewController is definitely being alloc'd, init'd, and loaded according to my log.

What could possibly be causing this bug? It seems so weird that I can simply flip CViewController's "Is Initial View Controller" property on the Storyboard and suddenly have the supported methods get called.

Here's the method I'm using to initiate the segue from a separate VC:

-(void)initCustomSegue
{
CViewController *newvc = [[CViewController alloc] init];
newvc.images = arrayOfImages;
newvc.distances = arrayOfDistances;
newvc.usernames = arrayOfUsers;
[self presentViewController:newvc animated:YES completion:nil];
}

I believe my class declaration is correctly formed:

@interface CViewController : UIViewController<UICollectionViewDataSource, UICollectionViewDelegateFlowLayout>

(Note: You don't need to redeclare the UICollectionViewDelegate because it is a subdelegate of UICollectionDelegateFlowLayout)

And I believe I'm setting up everything in ViewDidLoad the correct way:

- (void)viewDidLoad 
{
NSLog(@"loaded cviewcontroller");
[super viewDidLoad];
[self.myCollectionView setDataSource:self];
[self.myCollectionView setDelegate:self];
[self.myCollectionView registerClass:[CollectionViewCell class] forCellWithReuseIdentifier:identifier];
[self.myCollectionView registerNib:[UINib nibWithNibName:@"CollectionViewCell" bundle:[NSBundle mainBundle]]
        forCellWithReuseIdentifier:identifier];
}

Since this code does work in some context you can safely assume that all of my variables are instantiated correctly and that all of my data is legit.

Any idea where I'm going wrong? I'm stumped.

EDIT:

My current workaround is to embed the original VC inside a Navigation Controller and then create a push segue in the storyboard from the original VC to the instance of CViewController on the storyboard.

I then tweaked my data-passing implementation and segue call so that I simply make a call to performSegueWithIdentifier: and then pass all of the variables in using the prepareForSegue: method.

This works but I'm still very curious what my original problem was exactly.


Solution

  • It seems that when you are presenting the ViewController, you're not using the Storyboard for instantiation, thus the outlets nor the view are not connected.

    In the Storyboard, give your ViewController an identifier, and then use it to instantiate the ViewController from your storyboard. Something like this:

    Set the identifier in the Storyboard

    -(void)initCustomSegue
    {
       CViewController *newvc = [[UIStoryboard storyboardWithName:storyboardName bundle:nil] instantiateViewControllerWithIdentifier:@"Identifier"];
       newvc.images = arrayOfImages;
       newvc.distances = arrayOfDistances;
       newvc.usernames = arrayOfUsers;
       [self presentViewController:newvc animated:YES completion:nil];
    }
    

    However, if you know that your ViewController is and will always be the initial of that Storyboard, you don't need to do the above, just use:

    CViewController *newvc = [[UIStoryboard storyboardWithName:storyboardName bundle:nil] instantiateInitialViewController];