index 0 beyond bounds for empty NSArray'

hi i got this error from a QR scanner it was an old code so i try my best to pass to swift 4.2


2018-10-30 17:30:26.105369-0600 qrtest[5870:1814650] [MC] System group container for systemgroup.com.apple.configurationprofiles path is /private/var/containers/Shared/SystemGroup/systemgroup.com.apple.configurationprofiles
2018-10-30 17:30:26.105684-0600 qrtest[5870:1814650] [MC] Reading from public effective user settings.
2018-10-30 17:30:31.668783-0600 qrtest[5870:1814650] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArray0 objectAtIndex:]: index 0 beyond bounds for empty NSArray'
*** First throw call stack:
(0x18e6dbef8 0x18d8a9a40 0x18e5ebee0 0x102997b38 0x1029aead8 0x10257e288 0x10257edf4 0x194806ae4 0x19480639c 0x191ccfdfc 0x191ced4cc 0x1034f8de4 0x1034fc1e0 0x10350ecac 0x103500cd8 0x103501bb4 0x103506914 0x18e66a1bc 0x18e665084 0x18e6645b8 0x1908d8584 0x1bb50cbc8 0x1025812c8 0x18e124b94)
libc++abi.dylib: terminating with uncaught exception of type NSException




this might be the cause


video = AVCaptureVideoPreviewLayer(session: session)
        video.frame = view.layer.bounds //this part as the error says 
        view.layer.addSublayer(video)
        self.view.bringSubviewToFront(square)
        session.startRunning()



this is the code

import AVFoundation
import UIKit

class ViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate {

    var video = AVCaptureVideoPreviewLayer()
    
    @IBOutlet var square: UIImageView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        
        let session = AVCaptureSession()
        let captureDevice = AVCaptureDevice.default(for: AVMediaType.video)
        do
        {
            let input = try AVCaptureDeviceInput(device: captureDevice!)
            session.addInput(input)
        }
        catch{
            print("error")
        }
        let output = AVCaptureMetadataOutput()
        session.addOutput(output)
        
        output.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
        // en el objecttype se puede con la cara para otra app
        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 != nil {
            if let object = metadataObjects[0] as? AVMetadataMachineReadableCodeObject{
                if object.type == AVMetadataObject.ObjectType.qr{
                    
                    let alert = UIAlertController(title: "QR code", message: object.stringValue, preferredStyle: .alert)
                    alert.addAction(UIAlertAction(title: "RETAKE", style: .default, handler: nil))
                    alert.addAction(UIAlertAction(title: "Copy", style: .default, handler: { (nil) in
                        //aqui especificar donde se va a ir la copia  en este caso se va a clipboard
                        UIPasteboard.general.string = object.stringValue
                    }))
                    
                    present(alert, animated: true, completion: nil)
                    
                    
                    
                    
                }
            }
        }
    }

}

any ideas?

Answered by QuinceyMorris in 337927022

In the exception message, the class it shows is "__NSArray0", which is of course a private subclass of NSArray, but it's almost certainly a constant empty array. The trick is to find where in your code you cause that to be created.


This line doesn't look right:


        if metadataObjects != nil && metadataObjects.count != nil {


because the compiler won't accept a comparison between an Int ("count") and nil.


FWIW, you can rewrite code like this:


if metadataObjects != nil && metadataObjects.count != nil {

if let object = metadataObjects[0] as? AVMetadataMachineReadableCodeObject{


as something like this:


if let object = metadataObjects?.first as? AVMetadataMachineReadableCodeObject {


It may look a bit strange, but it coalesces all the optionals in one place, so in the end it's a more readable test.


Anyway, you should try to find out where the exception is thrown by symbolicating your crash log, or running the app through the debugger.

Accepted Answer

In the exception message, the class it shows is "__NSArray0", which is of course a private subclass of NSArray, but it's almost certainly a constant empty array. The trick is to find where in your code you cause that to be created.


This line doesn't look right:


        if metadataObjects != nil && metadataObjects.count != nil {


because the compiler won't accept a comparison between an Int ("count") and nil.


FWIW, you can rewrite code like this:


if metadataObjects != nil && metadataObjects.count != nil {

if let object = metadataObjects[0] as? AVMetadataMachineReadableCodeObject{


as something like this:


if let object = metadataObjects?.first as? AVMetadataMachineReadableCodeObject {


It may look a bit strange, but it coalesces all the optionals in one place, so in the end it's a more readable test.


Anyway, you should try to find out where the exception is thrown by symbolicating your crash log, or running the app through the debugger.

That could well be your metadataObjects array which is empty.


        if metadataObjects != nil && metadataObjects.count != nil {
            if let object = metadataObjects[0] as? AVMetadataMachineReadableCodeObject{


As Quincey told, the test

metadataObjects.count != nil is wrong: the test is always true, even if count is 0.


You probably meant

metadataObjects.count > 0


Hence the crash

Quincey provided the solution for it.

thanks

thanks amigo 😀

index 0 beyond bounds for empty NSArray'
 
 
Q