Пользовательский цикл событий и элементы управления UIKit. Какой дополнительный магический цикл событий Apple делает? - PullRequest
9 голосов
/ 07 апреля 2010

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

Мы используем пользовательский цикл событий в нашей игровой платформе iPhone на основе OpenGL. Он вызывает нашу систему рендеринга игр, вызывает 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;
    }
  }
}

1 Ответ

4 голосов
/ 11 мая 2010

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...