4

I have many places in my code where I need to do stuff based upon the layout of the views in a UIViewController. For example, I have a view in a nib that I then capture in code and use to create a mask for another layer, but I need to wait until the mask view and its subviews have the correct size before I do so.

I have discovered that, although hacky, I can achieve this by creating a counter which increments each time viewDidLayoutSubviews is called, and triggers the code I wish to execute when it has been called for the second time - for some reason, most of the views have yet to properly lay themselves out until viewDidLayoutSubviews is called for the second time.

Like I say, this seems pretty hacky and there's every chance that an iOS update could break my code. Does anyone have a better way of doing this?

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.layoutCount = 0;
}

- (void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];
    self.layoutCount ++;
    if (self.layoutCount == 2)
    {
        // perform final layout code, e.g. create masks
    }
}
jowie
  • 7,877
  • 8
  • 52
  • 92
  • I think you should save it for -viewWillAppear: – Jef Jul 07 '15 at 08:27
  • 2
    @Jef `viewWillAppear` is too early. It is called before `viewDidLayoutSubviews` is called even for the first time. Not all subview frames are correct at this point. – jowie Jul 07 '15 at 08:37
  • Keep your code such that it can adjust to the the method being called multiple times. For eg. Add the mask to view in viewWillAppear and set its frame in viewWillLayoutSubviews – jarora Jul 07 '15 at 09:13
  • It's not how UIKit works by default, everything should be layed out at the first call of `viewDidLayoutSubviews`. Probably you are adding something to your view hierarchy after that or modifying layout in some ways. Look into that, what's calling `viewDidLayoutSubviews` for the second time. – NKorotkov Jul 07 '15 at 10:47
  • I could do. It's difficult to work out what is getting it to be called for the second time because the trace log won't show that. But it may or may not be called an arbitrary number of times. So I guess the solution is to just regenerate the mask every time it is called. – jowie Jul 07 '15 at 16:18
  • @jarora cannot just update frame for the mask. The mask would have to be recreated every time from scratch. – jowie Jul 07 '15 at 16:19

1 Answers1

1

The safest approach might be to "refresh" the masks every time viewDidLayoutSubviews is called. this way you don't have to worry about whether the views have laid out or not.

ShahiM
  • 3,068
  • 1
  • 27
  • 54
  • That might be possible, however it is running some GPU Image filter calculations in order to create the mask. Running it twice (or multiple times) wouldn't be particularly efficient. But it may be better in terms of future compatibility... – jowie Jul 07 '15 at 16:11