Пользовательский цикл событий и средства управления UIKit. Что делает цикл событий дополнительной волшебной Apple?

Кто-либо знает или имеет хорошие ссылки, которые объясняют, что цикл событий iPhone делает под капотом?

Мы используем пользовательский цикл событий в нашей основанной на OpenGL игровой платформе iPhone. Это называет нашу игровую систему рендеринга, называет presentRenderbuffer и качает использование событий CFRunLoopRunInMode. См. код ниже для деталей.

Это работает хорошо, когда мы не используем средства управления UIKit (как доказательство, попробуйте Facetap, нашу первую выпущенную игру).

Однако при использовании средств управления UIKit, все почти работает, но не совсем. А именно, прокрутка средств управления UIKit не работает правильно.

Например, давайте рассмотрим следующий сценарий.

  • Мы показываем UIImagePickerController сверх нашего собственного представления.
  • UIImagePickerController покрывает наше пользовательское представление
  • Мы также приостанавливаем наш собственный рендеринг, но продолжаем использовать пользовательский цикл событий.

Как сказано, все работает, кроме прокрутки.

  • Выбор фото работ.
  • Развертка к работам фотоальбомов и анимациям перехода является гладкой.
  • При попытке прокрутить представление фотоальбома, представление следует пальцем.

Проблема: при прокрутке, прокрутке остановок сразу после того, как Вы шевелите пальцем. Обычно, это продолжается гладко на основе скорости Вашего перемещения, но не, когда мы используем пользовательский цикл событий. Кажется, что цикл событий iPhone делает некоторое волшебство, связанное с прокруткой UIKit этого, мы не реализовали нас.

Теперь, мы можем заставить средства управления UIKit работать просто великолепно и денди вместе с нашей собственной системой при помощи цикла событий и вызова Apple нашего собственного рендеринга через обратные вызовы NSTimer. Однако я все еще хотел бы понять, что возможно происходит в цикле событий iPhone, который не реализован в нашем пользовательском цикле событий.

- (void)customEventLoop { OBJC_METHOD;
  float excess = 0.0f;
  while(isRunning) {
    animationInterval = 1.0f / openGLapp->ticks_per_second();

    // Calculate the target time to be used in this run of loop
    float wait = max(0.0, animationInterval - excess); 
    Systemtime target = Systemtime::now().after_seconds(wait);

    Scope("event loop");

    NSAutoreleasePool* pool = [[ NSAutoreleasePool alloc] init];

    // Call our own render system and present render buffer 
    [self drawView];
    // Pump system events
    [self handleSystemEvents:target];

    [pool release];

    excess = target.seconds_to_now();
  }
}

- (void)drawView { OBJC_METHOD;

  // call our own custom rendering
  bool bind = openGLapp->app_render();

  // bind the buffer to be THE renderbuffer and present its contents
  if (bind) {
    opengl::bind_renderbuffer(renderbuffer);
    [context presentRenderbuffer:GL_RENDERBUFFER_OES];
  }
}

- (void) handleSystemEvents:(Systemtime)target { OBJC_METHOD;
  SInt32 reason = 0;
  double time_left = target.seconds_since_now();
  if (time_left <= 0.0) {
    while((reason = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, TRUE)) == kCFRunLoopRunHandledSource) {}
  } else {
    float dt = time_left;
    while((reason = CFRunLoopRunInMode(kCFRunLoopDefaultMode, dt, FALSE)) == kCFRunLoopRunHandledSource) {
      double time_left = target.seconds_since_now();
      if (time_left <= 0.0) break;
      dt = (float) time_left;
    }
  }
}

9
задан Paul Sweatte 7 October 2014 в 08:14
поделиться

1 ответ

Если вы NSLog [[NSRunLoop currentRunLoop] currentMode] из [UIScrollView setContentOffset: ] когда [UIScrollView isDecelerating] равно true, вы увидите UITrackingRunLoopMode.

В целом, система будет использовать режимы помимо kCFRunLoopDefaultMode на основном цикле выполнения потока UI, только некоторые из них документированы. Единственный способ получить полное поведение системы - это взаимодействовать с циклом выполнения системы на основном потоке.

Вы можете попробовать использовать NSTimer и позволить системе вызывать вас вместо того, чтобы самому вызывать CFRunLoopRunInMode. NSTimer может свободно работать с течением времени, и когда не отображается никакой другой пользовательский интерфейс, цикл выполнения системы не будет делать ничего, кроме вызова таймера.

Альтернативой может быть возврат из вашей функции customEventLoop во время отображения системных элементов управления и повторный вызов ее при возобновлении работы пользовательского интерфейса.

4
ответ дан 3 November 2019 в 07:47
поделиться
Другие вопросы по тегам:

Похожие вопросы: