Search code examples
iosswiftsegueisbn

iOS/Swift - Crazy Segue


I want to scan ISBN code (book identifier) to population the view before. So I perform a segue back to the view where I come from.

And the crazy thing happened. I see my view, and the application when back to the login view (initial view), login automatically as excepted (coz already register) and stop at the tableView where you have the add button for adding a new book.

I don't understand why after my BookVC my app jump to the initial VC ?

ScanBookViewController.swift :

class ScanBookViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate {

    var book = Book()

    var captureSession: AVCaptureSession!
    var previewLayer: AVCaptureVideoPreviewLayer!

    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = UIColor.blackColor()
        captureSession = AVCaptureSession()

        let videoCaptureDevice = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
        let videoInput: AVCaptureDeviceInput

        do {
            videoInput = try AVCaptureDeviceInput(device: videoCaptureDevice)
        } catch {
            return
        }

        guard captureSession.canAddInput(videoInput) else {
            alertPopUp("Scanning not supported", message: "Your device does not support scanning a code from an item. Please use a device with a camera.")
            captureSession = nil
            return
        }
        captureSession.addInput(videoInput)

        let metadataOutput = AVCaptureMetadataOutput()

        guard captureSession.canAddOutput(metadataOutput) else {
            alertPopUp("Scanning not supported", message: "Your device does not support scanning a code from an item. Please use a device with a camera.")
            captureSession = nil
            return
        }
        captureSession.addOutput(metadataOutput)
        metadataOutput.setMetadataObjectsDelegate(self, queue: dispatch_get_main_queue())
        metadataOutput.metadataObjectTypes = [AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeEAN13Code]

        previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
        previewLayer.frame = view.layer.bounds
        previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
        view.layer.addSublayer(previewLayer)

        captureSession.startRunning()
    }

    func alertPopUp(title:String, message:String) {
        let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.Alert)
        alert.addAction(UIAlertAction(title: "OK", style: .Default, handler: { (action) -> Void in
            self.dismissViewControllerAnimated(true, completion: nil)
        }))
        self.presentViewController(alert, animated: true, completion: nil)
    }

    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)

        if (captureSession?.running == false) {
            captureSession.startRunning()
        }
    }

    override func viewWillDisappear(animated: Bool) {
        super.viewWillDisappear(animated)

        if (captureSession?.running == true) {
            captureSession.stopRunning()
        }
    }

    func captureOutput(captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [AnyObject]!, fromConnection connection: AVCaptureConnection!) {
        captureSession.stopRunning()

        if let metadataObject = metadataObjects.first {
            let readableObject = metadataObject as! AVMetadataMachineReadableCodeObject

            AudioServicesPlaySystemSound(SystemSoundID(kSystemSoundID_Vibrate))
            foundCode(readableObject.stringValue)
        }

        dismissViewControllerAnimated(true, completion: nil)
    }


    func foundCode(code: String) {
        book.setISBN(code)
        book.setTitle("Super Titre")
        book.setAuthor("Gil Felot")
        book.setCover(UIImage(named: "iu.png")!)
        performSegueWithIdentifier("infoFinded", sender: nil)
    }

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {

        if segue.identifier == "infoFinded" {
            let bookVC: BookViewController = segue.destinationViewController as! BookViewController
            bookVC.book = book
        }
    }

    override func prefersStatusBarHidden() -> Bool {
        return true
    }

    override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
        return .Portrait
    }
}

BookViewController.swift :

class BookViewController: UIViewController {

    var book:Book!

    @IBOutlet weak var bookImage: UIImageView!
    @IBOutlet weak var bookTable: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()
        if book == nil {
            print("test segue")
            performSegueWithIdentifier("scanCode", sender: nil)
        } else {
            bookImage.image = book.getCover()
        }

        // Do any additional setup after loading the view.
    }

    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)

    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


}

Any idea, because I don't even know where to look at !


Solution

  • When you set up the segue did you select show (aka push) or did select modal? The standard way of handling passing data is through delegation. Create a protocol and declare a delegate in ScanBookViewController. Then set BookViewController as the delegate. Call the delegate method once you've scanned the book then pop or dismiss the scanBookViewController.

    protocol ScanBookDelegate{
    
        func didScanBook(scannedBook: Book)
    }
    
    class ScanBookViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate {
    
        var book = Book()
        var delegate: ScanBookDelegate? // create a new delegate instance
        var captureSession: AVCaptureSession!
        var previewLayer: AVCaptureVideoPreviewLayer!
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            view.backgroundColor = UIColor.blackColor()
            captureSession = AVCaptureSession()
    
            let videoCaptureDevice = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
            let videoInput: AVCaptureDeviceInput
    
            do {
                videoInput = try AVCaptureDeviceInput(device: videoCaptureDevice)
            } catch {
                return
            }
    
            guard captureSession.canAddInput(videoInput) else {
                alertPopUp("Scanning not supported", message: "Your device does not support scanning a code from an item. Please use a device with a camera.")
                captureSession = nil
                return
            }
            captureSession.addInput(videoInput)
    
            let metadataOutput = AVCaptureMetadataOutput()
    
            guard captureSession.canAddOutput(metadataOutput) else {
                alertPopUp("Scanning not supported", message: "Your device does not support scanning a code from an item. Please use a device with a camera.")
                captureSession = nil
                return
            }
            captureSession.addOutput(metadataOutput)
            metadataOutput.setMetadataObjectsDelegate(self, queue: dispatch_get_main_queue())
            metadataOutput.metadataObjectTypes = [AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeEAN13Code]
    
            previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
            previewLayer.frame = view.layer.bounds
            previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
            view.layer.addSublayer(previewLayer)
    
            captureSession.startRunning()
        }
    
        func alertPopUp(title:String, message:String) {
            let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.Alert)
            alert.addAction(UIAlertAction(title: "OK", style: .Default, handler: { (action) -> Void in
                self.dismissViewControllerAnimated(true, completion: nil)
            }))
            self.presentViewController(alert, animated: true, completion: nil)
        }
    
        override func viewWillAppear(animated: Bool) {
            super.viewWillAppear(animated)
    
            if (captureSession?.running == false) {
                captureSession.startRunning()
            }
        }
    
        override func viewWillDisappear(animated: Bool) {
            super.viewWillDisappear(animated)
    
            if (captureSession?.running == true) {
                captureSession.stopRunning()
            }
        }
    
        func captureOutput(captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [AnyObject]!, fromConnection connection: AVCaptureConnection!) {
            captureSession.stopRunning()
    
            if let metadataObject = metadataObjects.first {
                let readableObject = metadataObject as! AVMetadataMachineReadableCodeObject
    
                AudioServicesPlaySystemSound(SystemSoundID(kSystemSoundID_Vibrate))
                foundCode(readableObject.stringValue)
            }
    
            dismissViewControllerAnimated(true, completion: nil)
        }
    
    
        func foundCode(code: String) {
            book.setISBN(code)
            book.setTitle("Super Titre")
            book.setAuthor("Gil Felot")
            book.setCover(UIImage(named: "iu.png")!)
            self.delegate?.didScanBook(book) //Call the delegate method
            self.navigationController?.popViewControllerAnimated(true)
        }
    
        override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    
            if segue.identifier == "infoFinded" {
                let bookVC: BookViewController = segue.destinationViewController as! BookViewController
                bookVC.book = book
            }
        }
    
        override func prefersStatusBarHidden() -> Bool {
            return true
        }
    
        override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
            return .Portrait
        }
    }
    
    class BookViewController: UIViewController,ScanBookDelegate {
    
        var book:Book!
    
        @IBOutlet weak var bookImage: UIImageView!
        @IBOutlet weak var bookTable: UITableView!
    
        override func viewDidLoad() {
            super.viewDidLoad()
            if book == nil {
                print("test segue")
                performSegueWithIdentifier("scanCode", sender: nil)
            } else {
                bookImage.image = book.getCover()
            }
    
            // Do any additional setup after loading the view.
        }
    
        override func viewWillAppear(animated: Bool) {
            super.viewWillAppear(animated)
    
        }
        override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { //set book view controller as delegate to scan book view controller
        if segue.destinationViewController is ScanBookViewController{
            let scanBookViewController:ScanBookViewController = segue.destinationViewController
            scanBookViewController.delegate = self
        }
    }
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
            // Dispose of any resources that can be recreated.
        }
    
        fun didScanBook(scannedBook:Book) //respond as delegate
        {
            self.book = scannedBook
        }
    
    
    
    }