Czy ktoś zna lub ma dobre linki, które wyjaśniają, co pętla zdarzeń iPhone'a działa pod maską?Niestandardowa pętla zdarzeń i elementy sterujące UIKit. Jaką dodatkową magiczną pętlę zdarzeń Apple?
Używamy niestandardowej pętli zdarzeń w ramach naszego iPhone gier opartych na OpenGL. Wywołuje nasz system renderowania gier, wywołuje presentRenderbuffer i pompuje zdarzenia za pomocą metody CFRunLoopRunInMode. Zobacz kod poniżej, aby uzyskać szczegółowe informacje.
Działa dobrze, gdy nie używamy kontrolek UIKit (jako dowód, wypróbuj Facetap, naszą pierwszą wydaną grę).
Jednak przy użyciu kontrolek UIKit wszystko działa prawidłowo, ale nie całkiem. W szczególności przewijanie kontrolek UIKit nie działa poprawnie.
Na przykład rozważmy następujący scenariusz.
- Pokazujemy UIImagePickerController na naszym własnym widoku.
- UIImagePickerController obejmuje nasz widok niestandardowy
- Wstrzymujemy również nasze własne renderowanie, ale nadal używamy niestandardowej pętli zdarzeń.
Jak już powiedziano, wszystko działa, z wyjątkiem przewijania.
- Wybieranie zdjęć działa.
- Wiercenie do albumów fotograficznych działa i animacje przejścia są gładka.
- Podczas próby przewinięcia widoku albumu zdjęć widok podąża za palcem.
Problem: podczas przewijania przewijanie zatrzymuje się natychmiast po podniesieniu palca. Zwykle działa płynnie w oparciu o szybkość twojego ruchu, ale nie wtedy, gdy używamy niestandardowej pętli zdarzeń. Wygląda na to, że pętla zdarzeń iPhone'a robi magię związaną z przewijaniem UIKit, którego sami nie zaimplementowaliśmy.
Teraz możemy uzyskać kontrolę UIKit, aby działała dobrze i elegancko razem z naszym własnym systemem, używając pętli zdarzeń Apple i wywołując nasze własne renderowanie za pośrednictwem wywołań NSTimer. Jednak nadal chciałbym zrozumieć, co się dzieje w pętli zdarzeń iPhone'a, która nie jest zaimplementowana w naszej niestandardowej pętli zdarzeń.
- (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;
}
}
}
Użyłem timerów do gry OpenGL i pomimo tego, co możesz najpierw pomyśleć, uzyskałem najwyższą liczbę klatek na sekundę przy użyciu tej metody. Wydaje się, że gra się znacznie lepiej z główną pętlą zdarzeń. –
Drawonward, dziękuję, uruchom tryby pętli wyjaśnia to wszystko. Stosujemy również podejście oparte na NSTimer i ma pewne anomalie z szybkimi animacjami. W systemie iPhone OS 3.1 dostępny jest program CADisplayLink, który może pomóc w rozwiązaniu problemu. –
z jakiegoś powodu nie mogę oznaczyć odpowiedzi jako zaakceptowanej. Pytanie to miało wcześniej nagrodę, ale odpowiedziałeś po zamknięciu polowania na bounty i wydaje się, że Stackoverflow uniemożliwia mi zaznaczenie odpowiedzi zaakceptowanej po tym. Dziwne. –