Кто-нибудь знает или имеет хорошие ссылки, которые объясняют, что цикл событий 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;
}
}
}