As interesting as a camera frame on your sample application is, it would be even more interesting if you could actually do something with the frames you're seeing on the camera screen. Learn how to access the frame processing delegate in AVFoundation, and how to convert its output into an iOS friendly image that any iOS developer can interact with in their application.
- [Instructor] Now that we've added a button to our UI, let's make sure we handle what happens when we tap the button on our UI to capture a still image. Go to the code where you declared your button. And underneath the line where you set the image of it, type in button.addTarget, and let auto-complete take care of the rest. For target, you'll select self. For the action, you'll type #selector(shutterButtonTapped). Once again, this is not a method that we have created yet, but you'll type this in and add it in just a moment.
For UI control events, you'll type in .touchUpInside. Now scroll down to your extension where you handle UI button functions. Underneath cancelButtonTapped, add a new function. And we'll call this @objc func shutterButtonTapped. Now that we have a method to call whenever the shutter button is tapped, we need to make sure we do what's next. For this, we know that our camera object is going to be what opens up the aperture on our iOS device, and actually captures a still image.
But, when the camera object captures the still image and modifies it and processes it, we need to pass it back to our view controller. In order to do this, we'll need to implement a second yet internal delegate inside of our camera object. Go to your Cmara.swift file, and scroll to the very top of the file. Underneath importing AVFoundation, you'll type in protocol CameraDelegate. It's important to point out that we're specifying access control on this delegate to be internal. The developer creating an application that would use this framework does not need to access this delegate, as this runs only internal functions.
You want to write a function called stillImageCaptured. The two parameters you'll pass in will be camera of type Camera, and image of type UIImage. This means that whenever we pass an image back from the camera to the CameraViewController, we know exactly which camera is responsible for capturing the image. Go underneath the declaration of your camera object, and type var delegate of type CameraDelegate, and mark it optional with a question mark, just like we did for our UI view controller delegate.
We want to make sure that this is nill, unless specified otherwise. Let's go back to our CameraViewController.swift file. Scroll up to your init function. We need to refactor this to make sure that we're handling the delegate properly. Delete what you have written before on line 62, and type let camera = camera with self. Underneath that type camera.delegate = self. Finally you'll type self.camera = camera.
After you've done this, scroll down to the bottom of your file. We're going to add another extension to handle the use of our camera delegate. Go to line 146, hit enter twice, and type extension CameraViewController that adheres to camera delegate, and open the parenthesis. Additionally, make sure that you mark this, that this will handle all of your CameraDelegate functions. Once you've added the stub for this function, for now we simply want to type print camera button tapped.
Later on we'll implement the actual logic for this, but we just want to check that the delegate is communicating properly back to the view controller. Now you want to go into your cameras.swift object, and scroll to your update function. Above your update function, go ahead and write a function called captureStillImage. For this, right now, all we need to type is if let delegate = self.delegate, then delegate.stillImageCaptured. Auto complete it.
For the camera, we'll select self. And since we don't have an image to pass back yet, but we just want to test communication, we'll simply type UI image with an empty constructor, so that we can pass back empty memory of the correct type. Go back to your CameraViewController.swift file, and go to the shutterButtonTapped function. Inside this function type, if let camera = self.camera camera.captureStillImage. Go ahead and build your sample application to make sure everything works properly.
Once you see that everything builds properly, now we're going to test to make sure that the delegate is communicating properly. Before you run your sample application, put a breakpoint on line 154 so that you can check to make sure that your breakpoint is triggered and you're actually printing the right statement. Once you see your camera UI pop up, go ahead and tap the shutter button. You'll notice that the animation for the button be depressed is right there because you've hit your breakpoint in Xcode. If you look back at Xcode, you'll notice that our breakpoint has been triggered.
This means that we've set up our delegate to communicate properly back with the view controller, and we can start to get AV foundation to capture our still image.
Along the way, he explains the differences and nuances between writing code for an application and for a reusable framework, as well as some of the fundamentals of AVFoundation, one of the core camera frameworks in iOS. David also shows how to refactor your code, understand Swift access control, develop an interface, and handle memory leaks, so your framework is ready to share with other developers.
- Creating your first build
- Making the camera work
- Creating a framework delegate
- Adding media
- Capturing images
- Correcting orientation
- Versioning and tagging releases in Git