【发布时间】:2018-02-08 22:05:41
【问题描述】:
我需要在全局范围内定义一些变量,以便通过我的 ViewController 类的各种函数可以访问它们。
我发现并关注了一些在线教程/文章/参考资料,它们解释了同一件事 - Swift、iOS、CoreML 和用于图像处理/分类的相机。其中不止一个说“我们知道变量将存在并具有这种数据类型,因此可以添加'!' ”。但是,刚学 Swift,我理解并愿意坚持不使用 '!' 的设计原则。
所以我开始用var varName : ClassType! 声明变量,然后在稍后的执行点设置值。它总是在被访问之前设置(这是我在其他文章中看到的隐式展开选项的“规则”之一)。
如果我在需要它们的函数中声明它们,则只有该函数可以访问它们。但我需要通过 ViewController 访问它们。
我的骨架结构:
import UIKit
import AVFoundation
class ViewController: UIViewController, AVCaptureVideoDataOutputSampleBufferDelegate {
// MARK: Global Variables
var layer: CALayer {
return viewCamera.layer
}
var isCameraRunning = false
// INIT Camera Variables. Used by multiple functions, so global scope
var cameraSession : AVCaptureSession!
var device : AVCaptureDevice!
var cameraLayer : AVCaptureVideoPreviewLayer!
var cameraOutput : AVCaptureVideoDataOutput!
var cameraInput : AVCaptureDeviceInput!
// MARK: IB Outlets
@IBOutlet weak var labelInfo: UILabel! // provides user with status info
@IBOutlet weak var viewCamera: UIView! // a simple UIView on the storyboard
override func viewDidLoad() {
super.viewDidLoad()
let tap = UITapGestureRecognizer(target: self, action: #selector(ViewController.viewCameraTap))
viewCamera.addGestureRecognizer(tap)
}
@objc func viewCameraTap() {
if isCameraRunning {
// STOP CAMERA (AND PROCESSING)
cameraRelease()
// RESET UI
labelInfo.text = "Default text"
} else {
// INIT CAMERA
// START CAMERA, contained within cameraInit()
// PROCESS IMAGE CLASSIFICATION, contained within captureOutput()
cameraInit()
// UPDATE UI
labelInfo.text = "Processing"
}
isCameraRunning = !isCameraRunning // Toggles the value after processing the function
}
// MARK: Camera Init & Release
func cameraInit() {
cameraSession = AVCaptureSession()
cameraSession.sessionPreset = AVCaptureSession.Preset.photo
device = AVCaptureDevice.default(for: AVMediaType.video)
do {
cameraInput = try AVCaptureDeviceInput(device: device!)
if cameraSession.canAddInput(cameraInput) {
cameraSession.addInput(cameraInput)
}
} catch {
print(error.localizedDescription)
}
cameraOutput = AVCaptureVideoDataOutput()
if cameraSession.canAddOutput(cameraOutput) {
cameraSession.addOutput(cameraOutput)
}
cameraLayer = AVCaptureVideoPreviewLayer(session: cameraSession)
cameraLayer?.videoGravity = .resizeAspectFill
cameraLayer.frame = layer.frame
cameraLayer.frame.origin = CGPoint(x: 0, y: 0)
layer.addSublayer(cameraLayer)
cameraOutput.setSampleBufferDelegate(self, queue: DispatchQueue(label: "videoQueue"))
cameraSession.startRunning()
}
func cameraRelease() {
if cameraSession != nil {
if cameraSession.isRunning {
cameraSession.stopRunning()
cameraSession.removeInput(cameraInput)
cameraSession.removeOutput(cameraOutput)
cameraOutput = nil
cameraLayer.removeFromSuperlayer()
cameraSession = nil
}
}
}
// MARK: Camera Capture
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
processCameraBuffer(sampleBuffer: sampleBuffer) { result in
print("result: \(result)")
}
}
func processCameraBuffer(sampleBuffer: CMSampleBuffer, completion: @escaping (Float) -> Void) {
var result : Float = 0.0
// some processing, etc...
completion(result)
}
}
使变量在范围内成为全局变量而不是隐式解包选项的最佳/首选/推荐方法是什么?
如果我设置如下变量:
var cameraSession : AVCaptureSession?
然后在cameraInit() 中,我不能使用guard let newVarName 或if let newVarName,因为此newVarName 对象的范围将受到限制,并且还会使用不同的名称。
在cameraInit() 的顶部,我可以输入:cameraSession = AVCaptureSession() 来初始化它。但所有未来对cameraSession 的引用都需要可选链接(即尾随'cameraSession?')
或者,在这种情况下,是否可以使用隐式解包选项?我知道在设置之前不会访问此变量,并且我知道它将具有的数据类型。
【问题讨论】:
-
这些不是全局变量,它们包含在类的实例中。范围就是那个实例。