Search code examples
objective-cdelaysetternsrunloopdelayed-execution

How does setNeedsLayout work?


I would like to know how Apple's -setNeedsLayout works.

I already know that it's more efficient than directly calling -layoutSubviews, since I might need to do that twice in a method.
And that's just what I need it for: some custom -setNeedsValidation for a view controller.
But how to realize such a feature?


Solution

  • I can't confirm that Apple does it exactly this way, but here is a way to do what you're looking for, and is likely similar to how setNeedsLayout is implemented. I haven't tested this (or even compiled it), but it should give an idea of how to attack the problem as a category on UIViewController. Like UIKit, this is completely thread-unsafe.

    static NSMutableSet sViewControllersNeedingValidation = nil;
    static BOOL sWillValidate = NO;
    
    @implementation UIViewController (Validation)
    + (void)load {
      sViewControllersNeedingValidation = [[NSMutableSet alloc] init];
    }
    
    - (void)setNeedsValidation {
      [sViewControllersNeedingValidation addObject:self];
    
      if (! sWillValidate) {
        sWillValidate = YES;
        // Schedule for the next event loop
        [[self class] performSelector:@selector(dispatchValidation) withObject:nil afterDelay:0];
      }
    }
    
    + (void)dispatchValidation {
      sWillValidate = NO;
      // The copy here is in case any of the validations call setNeedsValidation.
      NSSet *controllers = [sViewControllersNeedingValidation copy];
      [sViewControllersNeedingValidation removeAllObjects];
      [controllers makeObjectsPerformSelector:@selector(validate)];
      [controllers release];
    }
    
    - (void)validate {
      // Empty default implementation
    }