Hi there team.
I have this issue, it makes things a little slower in runnning conditions
i have a QR scanner
func metadataOutput (_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
if metadataObjects != nil && metadataObjects.count != 0 {
if let object = metadataObjects[0] as? AVMetadataMachineReadableCodeObject {
if object.type == AVMetadataObject.ObjectType.qr {
//this is where the problem starts
let alert = UIAlertController(title: "Your code is:", message: object.stringValue, preferredStyle: .alert)
if object.stringValue == "1"{
self.performSegue(withIdentifier: "sendToAsistente", sender: nil)
}
else if object.stringValue == "2"{
self.performSegue(withIdentifier: "sendToExpositor", sender: nil)
}
else{
print("nada jeje")
}
alert.addAction(UIAlertAction(title: "Retake", style: .default, handler: nil))
alert.addAction(UIAlertAction(title: "Copy", style: .default, handler: { (nil) in
UIPasteboard.general.string = object.stringValue
}))
self.present(alert, animated: true, completion: nil)
}
}
}
}
my Alert is making this issue happend
et object = metadataObjects[0] as? AVMetadataMachineReadableCodeObject {
if object.type == AVMetadataObject.ObjectType.qr {
//this is where the problem starts
let alert = UIAlertController(title: "Your code is:", message: object.stringValue, preferredStyle: .alert)
if object.stringValue == "1"{
self.performSegue(withIdentifier: "sendToAsistente", sender: nil)
}
else if object.stringValue == "2"{
self.performSegue(withIdentifier: "sendToExpositor", sender: nil)
}
else{
i have tried to
DispatchQueue.main.async {
}
but it didn't work
if object.type == AVMetadataObject.ObjectType.qr {
let alert = UIAlertController(title: "Your code is:", message: object.stringValue, preferredStyle: .alert)
if object.stringValue == "1"{
DispatchQueue.main.async {
self.performSegue(withIdentifier: "sendToAsistente", sender: nil)
}
}
else if object.stringValue == "2"{
DispatchQueue.main.async {
self.performSegue(withIdentifier: "sendToExpositor", sender: nil)
}
}
gives me this error :
Warning: Attempt to present ContainerViewController: 0x145e4020> on ViewController: 0x146818b0> which is already presenting <UIAlertController: 0x14957a00>
that's the error what i'm missing?
whole code
import UIKit
import AVFoundation
class RegistroViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate {
//
//
@IBOutlet weak var square: UIImageView!
var video = AVCaptureVideoPreviewLayer()
var alertController: UIAlertController?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
//Creating session
let session = AVCaptureSession()
//Define capture devcie
let defaultDevice = AVCaptureDevice.default(for: AVMediaType.video)
do
{
let input = try AVCaptureDeviceInput(device: defaultDevice!)
session.addInput(input)
}
catch
{
print ("ERROR")
}
let output = AVCaptureMetadataOutput()
session.addOutput(output)
output.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
output.metadataObjectTypes = [AVMetadataObject.ObjectType.qr]
video = AVCaptureVideoPreviewLayer(session: session)
video.frame = view.layer.bounds
view.layer.addSublayer(video)
self.view.bringSubviewToFront(square)
session.startRunning()
}
func metadataOutput (_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
if metadataObjects != nil && metadataObjects.count != 0 {
if let object = metadataObjects[0] as? AVMetadataMachineReadableCodeObject {
if object.type == AVMetadataObject.ObjectType.qr {
let alert = UIAlertController(title: "Your code is:", message: object.stringValue, preferredStyle: .alert)
if object.stringValue == "1"{
self.performSegue(withIdentifier: "sendToAsistente", sender: nil)
}
else if object.stringValue == "2"{
self.performSegue(withIdentifier: "sendToExpositor", sender: nil)
}
else{
print("nada jeje")
}
alert.addAction(UIAlertAction(title: "Retake", style: .default, handler: nil))
alert.addAction(UIAlertAction(title: "Copy", style: .default, handler: { (nil) in
UIPasteboard.general.string = object.stringValue
}))
self.present(alert, animated: true, completion: nil)
}
}
}
}
//laaaaaaassssstttt
}
this is the error
Warning: Attempt to present <UIAlertController: 0x183c3a00> on <Conappeme.RegistroViewController: 0x17e7fc70> whose view is not in the window hierarchy!
The problem is that the delegate method is called more that one, so you need to ensure that there is not already an alertController presented before present another one.
Also you don't need to use:
DispatchQueue.main.async {
}
Because you indicated that you would like to use the main queue for the delegate methods:
captureMetadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
The following code take into account if there is already an alertController presented.
import UIKit
import AVFoundation
class ViewController: UIViewController {
@IBOutlet weak var squareView: UIImageView!
var video = AVCaptureVideoPreviewLayer()
var alertController: UIAlertController?
override func viewDidLoad() {
super.viewDidLoad()
//Creating session
let captureSession = AVCaptureSession()
//Define capture devcie
let defaultDevice = AVCaptureDevice.default(for: AVMediaType.video)
do {
let input = try AVCaptureDeviceInput(device: defaultDevice!)
captureSession.addInput(input)
}
catch {
print ("ERROR")
}
let captureMetadataOutput = AVCaptureMetadataOutput()
captureSession.addOutput(captureMetadataOutput)
captureMetadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
captureMetadataOutput.metadataObjectTypes = [AVMetadataObject.ObjectType.qr]
video = AVCaptureVideoPreviewLayer(session: captureSession)
video.frame = view.layer.bounds
view.layer.addSublayer(video)
view.bringSubviewToFront(squareView)
captureSession.startRunning()
}
}
extension ViewController : AVCaptureMetadataOutputObjectsDelegate{
func metadataOutput(_ captureMetadataOutput: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
// if metadataObjects != nil && metadataObjects.count != 0 { // WARNING: Comparing non-optional value of type '[AVMetadataObject]' to nil always returns true
guard metadataObjects.count != 0 else {
return
}
guard let object = metadataObjects[0] as? AVMetadataMachineReadableCodeObject else {
return
}
guard object.type == AVMetadataObject.ObjectType.qr else {
return
}
guard alertController == nil else {
print("There is already an alert presented")
return
}
alertController = UIAlertController(title: "Your code is:", message: object.stringValue, preferredStyle: .alert)
if object.stringValue == "1"{
self.performSegue(withIdentifier: "sendToAsistente", sender: nil)
} else if object.stringValue == "2"{
self.performSegue(withIdentifier: "sendToExpositor", sender: nil)
} else{
print("nada jeje")
}
guard let alert = alertController else {
return
}
alert.addAction(UIAlertAction(title: "Retake", style: .default, handler: { [weak self] (nil) in
guard let self = self else { return }
self.alertController = nil
}))
alert.addAction(UIAlertAction(title: "Copy", style: .default, handler: { [weak self] (nil) in
guard let self = self else { return }
self.alertController = nil
UIPasteboard.general.string = object.stringValue
}))
present(alert, animated: true, completion: nil)
}
}