Как работает setNeedsLayout?

#objective-c #delay #setter #nsrunloop #delayed-execution

#objective-c #задержка #установщик #nsrunloop #отложенное выполнение

Вопрос:

Я хотел бы знать, как -setNeedsLayout работает Apple.

Я уже знаю, что это более эффективно, чем прямой вызов -layoutSubviews , поскольку мне может потребоваться сделать это дважды в методе.
И это именно то, для чего мне это нужно: некоторые настройки -setNeedsValidation для контроллера представления.
Но как реализовать такую функцию?

Ответ №1:

Я не могу подтвердить, что Apple делает это именно так, но вот способ сделать то, что вы ищете, и, вероятно, похож на то, как setNeedsLayout это реализовано. Я не тестировал это (или даже не компилировал его), но это должно дать представление о том, как атаковать проблему как категорию UIViewController . Как и UIKit, это полностью небезопасно для потоков.

 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
}
  

Ответ №2:

Просто размышляю вслух… В документации говорится, что -setNeedsLayout обновление макета планируется в следующем «цикле обновления» (или «обновлении чертежа», как указано в -layoutSubviews документах).

Поэтому -setNeedsLayout , скорее всего, устанавливает BOOL флаг. Флаг проверяется позже (в -drawRect: ?) и, если он установлен YES , -layoutSubviews вызывается. Затем флаг сбрасывается и ожидает следующих вызовов -setNeedsLayout .

Комментарии:

1. Это именно то, что я подумал. Итак, как мне создать метод, который будет выполняться на следующей итерации основного цикла выполнения?

2. -performSelector:withObject:afterDelay: с нулевой задержкой планирует выполнение селектора в цикле выполнения.

3. Хорошо, это было очевидно. Извините.