1

I am trying to take a picture every 2 seconds by using a while loop. but when I try this the screen freezes.
This is the function that takes the photo:

func didPressTakePhoto(){

    if let videoConnection = stillImageOutput?.connectionWithMediaType(AVMediaTypeVideo){
        videoConnection.videoOrientation = AVCaptureVideoOrientation.Portrait
        stillImageOutput?.captureStillImageAsynchronouslyFromConnection(videoConnection, completionHandler: {
            (sampleBuffer, error) in

            if sampleBuffer != nil {


                let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(sampleBuffer)
                let dataProvider  = CGDataProviderCreateWithCFData(imageData)
                let cgImageRef = CGImageCreateWithJPEGDataProvider(dataProvider, nil, true, .RenderingIntentDefault)

                let image = UIImage(CGImage: cgImageRef!, scale: 1.0, orientation: UIImageOrientation.Right)

                UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)

                //Adds every image taken to an array each time the while loop loops which will then be used to create a timelapse.
                self.images.append(image)


            }


        })
    }


}

To take the picture I have a button which will use this function in a while loop when a variable called count is equal to 0, but when the end button is pressed, this variable is equal to 1, so the while loop ends.
This is what the startPictureButton action looks like:

@IBAction func TakeScreanshotClick(sender: AnyObject) {

    TipsView.hidden = true
    XBtnTips.hidden = true

    self.takePictureBtn.hidden = true

    self.stopBtn.hidden = false

    controls.hidden = true
    ExitBtn.hidden = true

    PressedLbl.text = "Started"
    print("started")

    while count == 0{

        didPressTakePhoto()

        print(images)
        pressed = pressed + 1
        PressedLbl.text = "\(pressed)"
        print(pressed)

        sleep(2)

    }


}

But when I run this and start the timelapse the screen looks frozen.
Does anyone know how to stop the freeze from happening - but also to add each image taken to an array - so that I can turn that into a video?

Andrew Harris
  • 396
  • 7
  • 24

2 Answers2

5

The problem is that the method that processes clicks on the button (TakeScreanshotClick method) is run on the UI thread. So, if this method never exits, the UI thread gets stuck in it, and the UI freezes.

In order to avoid it, you can run your loop on the background thread (read about NSOperation and NSOperationQueue). Occasionally you might need to dispatch something from the background thread to the UI thread (for instance, commands for UI updates).

UPDATE: Apple has a really great documentation (best of what I've seen so far). Have a look at this: Apple Concurrency Programming Guide.

FreeNickname
  • 7,398
  • 2
  • 30
  • 60
  • @AndrewHarris, unfortunately, it's a bit long to write (considering that operation cancellation should be taken care of), and I don't have much time right now. May be someone else will do it. Still, if you search information about asynchronious interfaces, you should be able to implement it. – FreeNickname Nov 08 '15 at 12:11
  • thanks, I did some research and found this, however I don't fully understand it, but it works partly, - dispatch_async(dispatch_get_main_queue()) {} and let priority = DISPATCH_QUEUE_PRIORITY_DEFAULT; dispatch_async(dispatch_get_global_queue(priority, 0)) { // do some task dispatch_async(dispatch_get_main_queue()) { // update some UI } } which seems to do the trick – Andrew Harris Nov 10 '15 at 08:03
  • @AndrewHarris, in order to understand concurrency on iOS better, take a look at this: [Apple Concurrency Programming Guide](https://developer.apple.com/library/ios/documentation/General/Conceptual/ConcurrencyProgrammingGuide/Introduction/Introduction.html). Apple has really great documentation (best of what I've seen so far). I don't know why I didn't think about this guide in the first place. It is not a ready solution, but it will help you to understand how it all works, so you won't have such problems in future. Good luck! Thanks for accepting my answer :) – FreeNickname Nov 10 '15 at 08:06
3

You are calling the sleep command on the main UI thread, thus freezing all other activity.

Also, I can't see where you set count = 1? Wouldn't the while loop continue forever?

Tim
  • 2,089
  • 1
  • 12
  • 21
  • thanks, @IBAction func StopClick(sender: AnyObject) { takePictureBtn.hidden = false stopBtn.hidden = true controls.hidden = false ExitBtn.hidden = false count = 1 print("stopped") pressed = 0 PressedLbl.text = "\(pressed)" print(images) } – Andrew Harris Nov 08 '15 at 10:22
  • sorry, forget that, count = 1 is in a separate button – Andrew Harris Nov 08 '15 at 10:28