当我尝试获取边界时,为啥 previewLayer 返回 nil?
Posted
技术标签:
【中文标题】当我尝试获取边界时,为啥 previewLayer 返回 nil?【英文标题】:Why is previewLayer returning nil when I try to get bounds?当我尝试获取边界时,为什么 previewLayer 返回 nil? 【发布时间】:2017-04-17 01:39:46 【问题描述】:正在从另一个故事板上的按钮调用此视图控制器。每次我点击按钮我都会得到
致命错误:在展开可选值时意外发现 nil 2017-04-16 21:00:39.929042 FaceOnACase[757:377279] 致命错误:在展开可选值时意外发现 nil
就行self.previewLayer?.frame = self.previewView.bounds.
我之前在我正在开发的一个单独的单视图应用程序中使用了此代码,但是当我将代码传输过来并连接 IBOutlets 时,由于某种原因我无法让它工作。
我找不到类似的问题,我不确定如何更正。任何帮助表示赞赏,谢谢。
import UIKit
import AVFoundation
class CaptureController: UIViewController, AVCapturePhotoCaptureDelegate
var captureSesssion: AVCaptureSession!
var cameraOutput: AVCapturePhotoOutput!
var previewLayer: AVCaptureVideoPreviewLayer!
@IBOutlet weak var capturedImage: UIImageView!
@IBOutlet weak var previewView: UIView!
override func viewDidLoad()
super.viewDidLoad()
captureSesssion = AVCaptureSession()
captureSesssion.sessionPreset = AVCaptureSessionPresetPhoto
cameraOutput = AVCapturePhotoOutput()
let device = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)
do
let input = try AVCaptureDeviceInput(device: device)
if (captureSesssion.canAddInput(input))
captureSesssion.addInput(input)
if (captureSesssion.canAddOutput(cameraOutput))
captureSesssion.addOutput(cameraOutput)
previewLayer = AVCaptureVideoPreviewLayer(session: captureSesssion)
self.previewLayer?.frame = self.previewView.bounds
previewView.layer.addSublayer(previewLayer)
captureSesssion.startRunning()
else
print("issue here : captureSesssion.canAddInput")
catch let error
print("error \(error.localizedDescription)")
// Take picture button
@IBAction func didPressTakePhoto(_ sender: UIButton)
let settings = AVCapturePhotoSettings()
let previewPixelType = settings.availablePreviewPhotoPixelFormatTypes.first!
let previewFormat = [
kCVPixelBufferPixelFormatTypeKey as String: previewPixelType,
kCVPixelBufferWidthKey as String: 160,
kCVPixelBufferHeightKey as String: 160
]
settings.previewPhotoFormat = previewFormat
cameraOutput.capturePhoto(with: settings, delegate: self)
// callBack from take picture
func capture(_ captureOutput: AVCapturePhotoOutput, didFinishProcessingPhotoSampleBuffer photoSampleBuffer: CMSampleBuffer?, previewPhotoSampleBuffer: CMSampleBuffer?, resolvedSettings: AVCaptureResolvedPhotoSettings, bracketSettings: AVCaptureBracketedStillImageSettings?, error: Error?)
if let error = error
print("error occured : \(error.localizedDescription)")
if let sampleBuffer = photoSampleBuffer,
let previewBuffer = previewPhotoSampleBuffer,
let dataImage = AVCapturePhotoOutput.jpegPhotoDataRepresentation(forJPEGSampleBuffer: sampleBuffer, previewPhotoSampleBuffer: previewBuffer)
print(UIImage(data: dataImage)?.size as Any)
let dataProvider = CGDataProvider(data: dataImage as CFData)
let cgImageRef: CGImage! = CGImage(jpegDataProviderSource: dataProvider!, decode: nil, shouldInterpolate: true, intent: .defaultIntent)
let image = UIImage(cgImage: cgImageRef, scale: 1.0, orientation: UIImageOrientation.right)
self.capturedImage.image = image
else
print("some error here")
// This method you can use somewhere you need to know camera permission state
func askPermission()
print("here")
let cameraPermissionStatus = AVCaptureDevice.authorizationStatus(forMediaType: AVMediaTypeVideo)
switch cameraPermissionStatus
case .authorized:
print("Already Authorized")
case .denied:
print("denied")
let alert = UIAlertController(title: "Sorry :(" , message: "But could you please grant permission for camera within device settings", preferredStyle: .alert)
let action = UIAlertAction(title: "Ok", style: .cancel, handler: nil)
alert.addAction(action)
present(alert, animated: true, completion: nil)
case .restricted:
print("restricted")
default:
AVCaptureDevice.requestAccess(forMediaType: AVMediaTypeVideo, completionHandler:
[weak self]
(granted :Bool) -> Void in
if granted == true
// User granted
print("User granted")
DispatchQueue.main.async()
//Do smth that you need in main thread
else
// User Rejected
print("User Rejected")
DispatchQueue.main.async()
let alert = UIAlertController(title: "WHY?" , message: "Camera it is the main feature of our application", preferredStyle: .alert)
let action = UIAlertAction(title: "Ok", style: .cancel, handler: nil)
alert.addAction(action)
self?.present(alert, animated: true, completion: nil)
)
【问题讨论】:
【参考方案1】:previewLayer
不返回nil
。是previewView
,即nil
。确保您已将其正确连接为情节提要中的插座。
你现在做的也太早了。您无法在 viewDidLoad
中启动捕获会话。请记住,这意味着视图存在,但它甚至还没有出现在界面中!您至少需要一个界面才能启动捕获会话。
【讨论】:
好的,我检查了,我把它正确连接了。现在,我应该把这些放在 viewWillAppear 中而不是 viewDidLoad 中吗? 因为现在一切似乎都在正常工作。谢谢顺便说一句! 我建议使用viewDidLayoutSubviews
,因为您依赖于self.previewView.bounds
,并且在此之前它不会被正确设置。您将需要一个 Bool 标志,以便您的代码只运行一次(因为 viewDidLayoutSubviews
被多次调用)。
因此,由于 viewDidLayoutSubviews 不需要 Bool arg,因此我将相机块(从 captureSession = AVCaptureSession() 开始到 do-try-catch 块的末尾)包装在 if 语句中,将像 loadCamera 这样的 var 设置为最初为 false,但如果完成则为 true?
因为当我连接插座并将它放在 viewDidLoad() 中时,它工作得很好(谢谢!),但是在我把它放入 viewDidLayoutSubviews() 之后,视图加载但相机不工作。再次感谢您的帮助!以上是关于当我尝试获取边界时,为啥 previewLayer 返回 nil?的主要内容,如果未能解决你的问题,请参考以下文章
类型“RelayObservable<unknown>”上不存在属性“then”。当我尝试在反应中使用中继获取数据时。我不知道为啥会出现这个错误