Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why won't RPScreenRecorder stopRecordingWithHandler work?

I am testing usability of a website and am using WKWebView in a native app. The reason for this is so that I can use COSTouchVisualizer to show the touches, and RPScreenRecorder to record the interaction and the 'talk out loud' with the mic.

I have the following IBAction to start the recording:

@IBAction func startRecordSession(sender: AnyObject) {

    let recorder = RPScreenRecorder.sharedRecorder()

    guard recorder.available else{
        print("Cannot record the screen")
        return
    }

    recorder.delegate = self

    recorder.startRecordingWithMicrophoneEnabled(true) { (err) in

        guard err == nil else{
            if err!.code ==
                RPRecordingErrorCode.UserDeclined.rawValue{
                print("User declined app recording")
            }
            else if err!.code ==
                RPRecordingErrorCode.InsufficientStorage.rawValue{
                print("Not enough storage to start recording")
            }
            else{
                print("Error happened = \(err!)")
            }
            return
        }

        print("Successfully started recording")
        self.recordBtn.enabled = false
        self.stopRecordBtn.enabled = true
    }

}

Which seems to work with the printing Successfully started recording.

However, when the button connected to the IBAction to stop recording is pressed the following code should run:

@IBAction func stop() {

  let recorder = RPScreenRecorder.sharedRecorder()

  print("1. before the recorder function")// This prints

  recorder.stopRecordingWithHandler{controller, err in     

    guard let previewController = controller where err == nil else {
      self.recordBtn.enabled = true
      self.stopRecordBtn.enabled = false

      print("2. Failed to stop recording")// This does not prints

      return
    }

    previewController.previewControllerDelegate = self

    self.presentViewController(previewController, animated: true,
      completion: nil)

  }

}

But nothing happens except to print out the first log ("1. before the recorder function"). I get non of the other log statements nor do the buttons toggle their enabled status.

I know the IBAction is connected due to hitting the statement but no idea why I can't get the stopRecordingWithHandler to fire.

I am testing this on an iPad Pro 9.7" running iOS 9.3.

I am starting to wonder if it has anything to do with trying to record a WKWebView but would imagine that I would get an error if this was the problem.

Any help would be greatly appreciated :)

like image 432
Shane Davis Avatar asked Apr 28 '16 13:04

Shane Davis


1 Answers

I suspect that if you were to set a breakpoint anywhere inside your guard statement (within stopRecordingCompletionHandler), it would not crash your program or enter the debugger because the else clause of your guard statement is never being called.

In fact, this is expected behavior. We would not expect the else clause to execute unless either controller is equal to nil and therefore cannot be bound to the constant previewController or error exists and therefore does not equal nil.

With guard, the only way the else clause will be called is if the specified conditions are NOT true. Your print statement in the startRecordingWithMicrophoneEnabled closure is being called because it is sitting outside of the guard statement.

So you just need to move some of that logic out of the else clause. You do still want to handle errors there though.

recorder.stopRecordingWithHandler{controller, err in     

      guard let previewController = controller where err == nil else {

          print("2. Failed to stop recording with error \(err!)") // This prints if there was an error

          return
      }
}

self.recordBtn.enabled = true
self.stopRecordBtn.enabled = false

previewController.previewControllerDelegate = self

self.presentViewController(previewController, animated: true,
  completion: nil)

print("stopped recording!")

Guard

So just to be sure we're clear on the guard syntax, it's:

guard <condition> else {
    <statements to execute if <condition> is not true>
}

In your example, you're combining guard with optional binding and a where clause, to create the following situation:

  • If controller is not nil, it will be bound to a constant called previewController.
  • If it is nil then we stop evaluating , never create the constant previewController, and escape to the else clause, which must transfer control with a keyword such as return.
  • If controller is not nil and our constant has been created then we will go ahead and check our where clause.
  • If where evaluates to true (so if there is no error), we will pass the test and be done with the guard statement. else will never be executed.
  • If where evaluates to false, we will execute the else block and anything after the guard statement will not be called.
like image 176
Matthew Seaman Avatar answered Oct 01 '22 15:10

Matthew Seaman