【问题标题】:Bewildered: Non-nil value unwrapped nil, if-let clause executes block on nil value困惑:非 nil 值解包 nil,if-let 子句在 nil 值上执行块
【发布时间】: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) 为什么如果 stillImageDatadetailItem 被赋予非 nil 值,它们是 nil,以及 2) 为什么 if-let 子句执行它的块?

【问题讨论】:

  • 顺便说一句,Data! 一个可选属性

标签: ios swift


【解决方案1】:

stillImageDatadetailItem 不是nil,但imageViewnil

prepare(for 中,在您执行controller.detailItem = stillImageData 的那一刻,目标控制器的视图尚未加载,因此所有出口都未连接。当在configureView() 中访问出口时,会发生崩溃。

在这种情况下,在viewDidLoad 中调用configureView()

var detailItem: Data? 

override func viewDidLoad() {
    super.viewDidLoad()
    configureView()
}

另一方面,如果detailItem 将被多次更新,请检查插座

var detailItem: Data? {
    didSet {
        if imageView != nil { configureView() }
    }
}

override func viewDidLoad() {
    super.viewDidLoad()
    configureView()
}

【讨论】:

  • 你是对的!编译器将我指向初始化程序的参数,但它是视图本身。谢谢!
猜你喜欢
  • 2015-04-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-04
  • 2020-12-07
  • 2023-03-20
  • 2023-03-17
  • 1970-01-01
相关资源
最近更新 更多