【发布时间】:2019-01-12 06:51:15
【问题描述】:
我将 Data 类型的非 nil 值分配给非可选属性,然后将其分配给可选属性,该属性最终用所述数据实例化图像。当可选项通过 if-let 子句时,它的块执行,抛出错误:
致命错误:在展开可选值时意外发现 nil
绝不应该 stillImageData 解开 nil。
import UIKit
import AVFoundation
import Photos
class ViewController: UIViewController, AVCapturePhotoCaptureDelegate {
var photoOutput: AVCapturePhotoOutput!
var stillImageData: Data!
@IBAction func handleTouch(_ sender: Any) {
let photoSettings = AVCapturePhotoSettings(format: nil)
photoSettings.isAutoStillImageStabilizationEnabled = true
if photoOutput.supportedFlashModes.contains(AVCaptureDevice.FlashMode.auto) {
photoSettings.flashMode = .auto
}
photoOutput.capturePhoto(with: photoSettings, delegate: self)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
switch AVCaptureDevice.authorizationStatus(for: .video) {
case .authorized: // The user has previously granted access to the camera.
self.setupCaptureSession()
case .notDetermined: // The user has not yet been asked for camera access.
AVCaptureDevice.requestAccess(for: .video) { granted in
if granted {
self.setupCaptureSession()
}
}
case .denied: // The user has previously denied access.
return
case .restricted: // The user can't grant access due to restrictions.
return
}
PHPhotoLibrary.requestAuthorization { status in
guard status == .authorized else { return }
// Use PHPhotoLibrary.shared().performChanges(...) to add assets.
}
}
func setupCaptureSession() {
let captureSession = AVCaptureSession()
// Connect inputs and outputs to the session
captureSession.beginConfiguration()
let videoDevice = AVCaptureDevice.default(.builtInWideAngleCamera,
for: .video, position: .unspecified)
guard
let videoDeviceInput = try? AVCaptureDeviceInput(device: videoDevice!),
captureSession.canAddInput(videoDeviceInput)
else { return }
captureSession.addInput(videoDeviceInput)
photoOutput = AVCapturePhotoOutput()
guard captureSession.canAddOutput(photoOutput) else { return }
captureSession.sessionPreset = .photo
captureSession.addOutput(photoOutput)
captureSession.commitConfiguration()
// Display a camera preview
let previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
previewLayer.frame = view.bounds
previewLayer.videoGravity = .resizeAspectFill
view.layer.addSublayer(previewLayer)
// Run the capture session
captureSession.startRunning()
}
// MARK: - Photo capture
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
// guard error != nil else { print("Error capturing photo: \(error!)"); return }
self.stillImageData = photo.fileDataRepresentation()
performSegue(withIdentifier: "showDetail", sender: self)
}
// MARK: - Navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showDetail" {
let controller = (segue.destination as! UINavigationController).topViewController as! RootViewController
controller.detailItem = stillImageData
}
}
}
import UIKit
import Photos
class RootViewController: UIViewController {
@IBOutlet weak var imageView: UIImageView!
func configureView() {
if let stillImageData = detailItem {
imageView.image = UIImage(data: stillImageData)
}
}
var detailItem: Data? {
didSet {
configureView()
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
@IBAction func dismissViewController(_ sender: Any) {
dismiss(animated: true, completion: nil)
}
@IBAction func savePhotoToPhotosLibrary(_ sender: Any) {
PHPhotoLibrary.requestAuthorization { status in
guard status == .authorized else { return }
PHPhotoLibrary.shared().performChanges({
// Add the captured photo's file data as the main resource for the Photos asset.
let creationRequest = PHAssetCreationRequest.forAsset()
creationRequest.addResource(with: .photo, data: self.detailItem!, options: nil)
}, completionHandler: { success, error in
if !success { NSLog("error creating asset: \(error!)") }
})
}
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
}
如果有人能伸出援手,我们将不胜感激。 1) 为什么如果 stillImageData 和 detailItem 被赋予非 nil 值,它们是 nil,以及 2) 为什么 if-let 子句执行它的块?
【问题讨论】:
-
顺便说一句,
Data!是一个可选属性