Ich verwende das offizielle Ricoh Theta iOS SDK (Link) in meiner App, um eine 360 ° Ricoh Theta Kamera anzuschließen. Das SDK verwendet mehrere HTTP-Anforderungen, um die Erfassung von Bildern auszulösen und Bilder von der Kamera herunterzuladen.Semaphore mit NSRunLoop funktioniert nicht seit Upgrade auf iOS10
Intern verwendet das SDK Semaphoren zum Synchronisieren der Anfragen, aber seit dem Upgrade auf iOS 10 scheint dies aus irgendeinem Grund nicht mehr zu funktionieren. Laut den Entwicklerforen ist das Problem bekannt, Ricoh scheint das aber nicht wirklich zu interessieren.
Ich habe es auf ein bestimmtes Teil im SDK eingegrenzt, wo das SDK in einer Schleife prüft, ob ein Bild verfügbar ist, indem eine Anfrage alle 0,5 Sekunden über eine RunLoop gesendet wird.
Dies geschieht in dieser Funktion:
/**
* Start status monitoring
* @param command ID of command to be monitored
* @return Status indicating completion or error
*/
- (NSString*)run:(NSString*)command
{
// Create and keep HTTP session
NSURLSessionConfiguration* config = [NSURLSessionConfiguration defaultSessionConfiguration];
_session= [NSURLSession sessionWithConfiguration:config];
_commandId = command;
// Semaphore for synchronization (cannot be entered until signal is called)
_semaphore = dispatch_semaphore_create(0);
// Create and start timer
NSTimer *timer = [NSTimer timerWithTimeInterval:0.5f
target:self
selector:@selector(getState:)
userInfo:nil
repeats:YES];
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addTimer:timer forMode:NSRunLoopCommonModes];
[runLoop run];
// Wait until signal is called
dispatch_semaphore_wait(_semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"HERE");
return _state;
}
Das Problem ist, dass NSLog(@"HERE");
nicht einmal genannt wird, obwohl die Semaphore in der getState Methode (dispatch_semaphore_signal(_semaphore);
) ausgelöst wird. Ich weiß das sicher, indem ich durch die Zeilen im Debugger gehe.
/**
* Delegate called during each set period of time
* @param timer Timer
*/
- (void)getState:(NSTimer*)timer {
// Create JSON data
NSDictionary *body = @{@"id": _commandId};
// Set the request-body.
[_request setHTTPBody:[NSJSONSerialization dataWithJSONObject:body options:0 error:nil]];
// Send the url-request.
NSURLSessionDataTask* task =
[_session dataTaskWithRequest:_request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (!error) {
NSArray* array = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
_state = [array valueForKey:@"state"];
_fileUri = [array valueForKeyPath:@"results.fileUri"];
NSLog(@"result: %@", _state);
} else {
_state = @"error";
NSLog(@"GetStorageInfo: received data is invalid.");
}
if (![_state isEqualToString:@"inProgress"]) {
[timer invalidate];
dispatch_semaphore_signal(_semaphore);
// Stop timer
[timer invalidate];
}
}];
[task resume]; }
Ich habe es gesehen haben einige kleinere Änderungen an der NSRunLoop in iOS 10, ist diese möglicherweise bezogen auf das, was ich hier gegenüber? Ein anderes Gefühl, das ich habe, ist, dass iOS vielleicht keinen neuen Thread bekommt, der dispatch_semaphore_wait
ruft.
Ich habe in den letzten paar Stunden meinen Kopf gegen den Tisch geschlagen, wirklich gehofft, dass einer von euch hier draußen helfen kann!
Vielen Dank für Ihre sehr detaillierte Antwort! Ich schätze das wirklich! Ich fand dieses Gist, das Ihrem vorgeschlagenen Ansatz folgen würde (https://gist.github.com/maicki/7622108), dennoch frage ich mich jetzt, wie man es in das vorhandene SDK einfügt. Mit einem Dispatch-Timer könnte ich gezwungenermaßen einen Completion-Block verwenden, aber das SDK gibt derzeit den Wert zurück, nachdem ich für den Semaphor synchron gewartet habe. Gibt es eine Möglichkeit, diese beiden Ansätze zu kombinieren? –
Sie würden immer noch den Semaphor verwenden. Es ist nur so, dass Sie den 'NSTimer' durch eine Dispatch-Timer-Quelle ersetzen und dann die Lauf-Schleife nicht ausführen müssen. –
Macht Sinn! Du hast mir den Tag gemacht, ernsthaft kann ich dir nicht genug danken! –