2016-06-08 8 views
0

Ich habe eine Funktion, um ein Foto mit der Kamera über die captureStillImageAsynchronouslyFromConnection() - Methode aufzunehmen. Das aufgenommene Bild ist mein Rückgabewert für die capture() - Methode.Wie bekomme ich das aufgenommene Foto zum Haupt-Thread?

Ich möchte das aufgenommene Foto in einer Variablen in meinem ViewController speichern und dann einen Übergang zu einem anderen ViewController durchführen, der das Foto zeigt. Das scheint nicht zu funktionieren, bekomme ich eine fatal error: unexpectedly found nil while unwrapping an Optional value - Fehler.

Ich weiß, dass es wegen var photo: UIImage! ist nil, aber wie kann ich die Fotodaten in meinem Haupt-Thread vor dem Aufruf der performSegue... Funktion bekommen?

Meine Fotofunktion (in meinem CameraSession-Klasse) und die Session-Warteschlange:

var sessionQueue = dispatch_queue_create("CameraSession", DISPATCH_QUEUE_SERIAL) 

func capture(saveToGallery save: Bool) -> UIImage { 
    var capturedImage = UIImage() 

    let connection = self.output.connectionWithMediaType(AVMediaTypeVideo) 
    connection.videoOrientation = .Portrait 

    dispatch_async(sessionQueue, { 
     self.output.captureStillImageAsynchronouslyFromConnection(
      connection, completionHandler: { 
       (imageDataSampleBuffer: CMSampleBuffer?, error: NSError?) -> Void in 
       if imageDataSampleBuffer != nil { 
        let imageData: NSData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(imageDataSampleBuffer) 
         self.capturedImage = UIImage(data: imageData) 

        if save { 
         UIImageWriteToSavedPhotosAlbum(self.capturedImage!, nil, nil, nil) 
        } 
       } 
      } 
     ) 
    }) 

    return self.capturedImage! 
} 

Meine Funktion in der Viewcontroller-Klasse:

func capture() { 
    let photo = cameraSession.capture(saveToGallery: true) 
    performSegueWithIdentifier("showPhoto", sender: self) // This will switch to another ViewController, which shows the captured photo. 
} 

Antwort

0

Da Sie das Foto asynchron Ihre aufnimmst Funktion erreicht

bevor das Foto aufgenommen wurde, und sel f.capturedImage ist null. Sie sollten Ihre Logik, die das Segment behandelt, nach der Rückgabe der Bilddaten verschieben. Dies ist wahrscheinlich am einfachsten durch Hinzufügen eines Callback als Argument für Ihre Capture-Methode zu erreichen:

func capture(saveToGallery save: Bool, callback:UIImage -> Void) -> Void 

und dann, anstatt direkt die UIImage zurückkehren, geben sie als Argument an Ihren Rückruf:

let imageData: NSData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(imageDataSampleBuffer) 
    self.capturedImage = UIImage(data: imageData) 

if save { 
    UIImageWriteToSavedPhotosAlbum(self.capturedImage!, nil, nil, nil) 
} 

callback(self.capturedImage) 

Ihre UIViewController Capture-Methode würde in etwa so aussehen:

func capture() { 
    let photo = cameraSession.capture(saveToGallery: true, callback: { 
    (photo: UIImage) -> Void in 
    //save your photo locally in your UIViewController class here if you need to 
    performSegueWithIdentifier("showPhoto", sender: self) 
    }) 
} 
+0

Das Bild wird nicht in einem Viewcontroller-Klasse genommen wird, so kann ich ein nicht hinzufügen Übergang zu ihm. Ist es möglich, meine Funktion zu zwingen, zu warten, bis "self.capturedImage" nicht null ist, und sie dann zurückzugeben? – user3653164

+0

Ich würde etwas wie das, was Gargoyle beschreibt, empfehlen und einen Block als zweites Argument an deine Capture-Methode übergeben. Meine Antwort wurde aktualisiert, um diese Idee widerzuspiegeln. – J2K

0

Fahren Sie mit Capture (_) Methode ein Block als zweiter Parameter, der eine UIImage nimmt. Wenn Sie das aufgenommene Bild erhalten haben, nachdem Sie es gespeichert haben, rufen Sie das Bild auf, das in Block übergeben wurde. Senden Sie es einfach an die Hauptwarteschlange, bevor Sie es anrufen. Dann würden Sie etwas mehr wie haben:

func capture() { 
    cameraSession.capture(saveToGallery: true) { 
     [unowned self] image in 
     self.myCapturedImage = image 
     self.performSegueWithIdentifier("showPhoto", sender: self) 
    } 
} 
+0

Welchen Teil meinen Sie, ich sollte es "in die Hauptwarteschlange schicken, bevor Sie es anrufen"? – user3653164

+0

Nachdem Sie das Bild in Ihrer Sitzungswarteschlange gespeichert haben. In dort eine dispatch_async zur Hauptwarteschlange und innerhalb dieses Dispatchblocks rufe den Block an dich übergeben – Gargoyle

+0

Ich bekomme immer noch den gleichen Fehler für die 'photo' Variable in meiner ViewController-Klasse. Es bleibt immer noch leer, auch wenn ich es mit einem Callback/Completion-Block und einem dispatch_async für meine "completion" (image: self.capturedImage!) Mache. – user3653164

0

Sie fordern die Haupt (UI) Gewinde wie folgt aus:

dispatch_async(dispatch_get_main_queue(), ^{ 
    //Do something in main thread 
}); 
Verwandte Themen