我正在将类型为Data的非nil值分配给非可选属性,然后将其分配给可选属性,该属性最终使用该数据实例化图像。当可选参数通过if-let子句时,它的块执行,并抛出错误:
致命错误:解开可选值时意外发现nil
绝对不要 stillImageData 拆零。
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子句执行其块?
答案 0 :(得分:1)
stillImageData
和detailItem
不是nil
,但是imageView
是nil
。
在执行prepare(for
时,在controller.detailItem = stillImageData
中尚未加载目标控制器的视图,因此尚未连接所有插座。在configureView()
中访问插座时,会发生崩溃。
在这种情况下,请在configureView()
中呼叫viewDidLoad
var detailItem: Data?
override func viewDidLoad() {
super.viewDidLoad()
configureView()
}
另一方面,如果detailItem
要多次更新,请检查插座
var detailItem: Data? {
didSet {
if imageView != nil { configureView() }
}
}
override func viewDidLoad() {
super.viewDidLoad()
configureView()
}