0

I am currently trying to move one variable from one class to another. I am using the AVFramework to read QR Codes. The QR Code ultimately reads to a string variable and then the string variable reads to a label.text. I would like to use this exact same text within the textview of another class.

QRScannerController houses the QR code while HistoryViewis where I'd like to re-use the variable. The problem is that once I scan the QR code and move to the History view, it reads nothing. Here is what I have so far. Below is the QRScannerController

func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?){   
    if segue.destination .isKind(of:HistoryView.self){
        let vc2 = segue.destination as! HistoryView
        vc2.previousViewController = self
    }
}

@IBOutlet var messageLabel:UILabel!
@IBOutlet var topbar: UIView!
@IBOutlet var segmentedControl: UISegmentedControl!
//@IBOutlet var textFacts: UITextView!


var captureSession:AVCaptureSession?
var videoPreviewLayer:AVCaptureVideoPreviewLayer?
var qrCodeFrameView:UIView?



let supportedCodeTypes = [AVMetadataObjectTypeUPCECode,
                    AVMetadataObjectTypeCode39Code,
                    AVMetadataObjectTypeCode39Mod43Code,
                    AVMetadataObjectTypeCode93Code,
                    AVMetadataObjectTypeCode128Code,
                    AVMetadataObjectTypeEAN8Code,
                    AVMetadataObjectTypeEAN13Code,
                    AVMetadataObjectTypeAztecCode,
                    AVMetadataObjectTypePDF417Code,
                    AVMetadataObjectTypeQRCode]

@IBAction func unwindToHomeScreen(segue: UIStoryboardSegue) {
    dismiss(animated: true, completion: nil)
}

override func viewDidLoad() {
    super.viewDidLoad()



    // Get an instance of the AVCaptureDevice class to initialize a device object and provide the video as the media type parameter.
    let captureDevice = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)

    do {
        // Get an instance of the AVCaptureDeviceInput class using the previous device object.
        let input = try AVCaptureDeviceInput(device: captureDevice)

        // Initialize the captureSession object.
        captureSession = AVCaptureSession()

        // Set the input device on the capture session.
        captureSession?.addInput(input)

        // Initialize a AVCaptureMetadataOutput object and set it as the output device to the capture session.
        let captureMetadataOutput = AVCaptureMetadataOutput()
        captureSession?.addOutput(captureMetadataOutput)

        // Set delegate and use the default dispatch queue to execute the call back
        captureMetadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
        captureMetadataOutput.metadataObjectTypes = supportedCodeTypes

        // Initialize the video preview layer and add it as a sublayer to the viewPreview view's layer.
        videoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
        videoPreviewLayer?.videoGravity = AVLayerVideoGravityResizeAspectFill
        videoPreviewLayer?.frame = view.layer.bounds
        view.layer.addSublayer(videoPreviewLayer!)

        // Start video capture.
        captureSession?.startRunning()

        // Move the message label and top bar to the front
        view.bringSubview(toFront: messageLabel)
        view.bringSubview(toFront: topbar)

        // Initialize QR Code Frame to highlight the QR code
        qrCodeFrameView = UIView()

        if let qrCodeFrameView = qrCodeFrameView {
            qrCodeFrameView.layer.borderColor = UIColor.green.cgColor
            qrCodeFrameView.layer.borderWidth = 2
            view.addSubview(qrCodeFrameView)
            view.bringSubview(toFront: qrCodeFrameView)
        }

    } catch {
        // If any error occurs, simply print it out and don't continue any more.
        print(error)
        return
    }

}

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



// MARK: - AVCaptureMetadataOutputObjectsDelegate Methods

public func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [Any]!, from connection: AVCaptureConnection!) {

    // Check if the metadataObjects array is not nil and it contains at least one object.
    if metadataObjects == nil || metadataObjects.count == 0 {
        qrCodeFrameView?.frame = CGRect.zero
        //messageLabel.text = "No QR/barcode is detected"
        return
    }


    // Get the metadata object.
    let metadataObj = metadataObjects[0] as! AVMetadataMachineReadableCodeObject


    if supportedCodeTypes.contains(metadataObj.type) {
        // If the found metadata is equal to the QR code metadata then update the status label's text and set the bounds
        let barCodeObject = videoPreviewLayer?.transformedMetadataObject(for: metadataObj)
        qrCodeFrameView?.frame = barCodeObject!.bounds

         if metadataObj.stringValue != nil {
            //captureSession?.stopRunning()

            messageLabel.text = metadataObj.stringValue
            messageLabel.text = messageLabel.text

            //let vc: UINavigationController = storyboard?.instantiateViewController(withIdentifier: "View") as! UINavigationController


            let vc3: UIViewController = storyboard!.instantiateViewController(withIdentifier: "View") //as! UIViewController

            self.present(vc3, animated: true, completion: nil)

        }
    }
}
func transferViewControllerVariables() -> (UILabel){
    return messageLabel
}
}

Here is the History View:

import UIKit
import AVFoundation

class HistoryView: UIViewController, AVCaptureMetadataOutputObjectsDelegate {

    @IBOutlet var textHistory:UITextView!
    var previousViewController: QRScannerController?


    @IBAction func unwindToHomeScreen(segue: UIStoryboardSegue) {
        dismiss(animated: true, completion: nil)
    }

    @IBAction func toMaps(segue: UIStoryboardSegue) {
        let vc3: UIViewController = storyboard!.instantiateViewController(withIdentifier: "front") //as! UIViewController

        self.present(vc3, animated: true, completion: nil)
    }


    override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.


        let  messageLabel = previousViewController?.transferViewControllerVariables()
        //print(messageLabel.text as Any)
        textHistory.text = messageLabel?.text

        }

        // Do any additional setup after loading the view.


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


}
rmaddy
  • 314,917
  • 42
  • 532
  • 579
CALVIN
  • 3
  • 2
  • Why you are not using segue but using `present` with `vc3` in `QRScannerController`? Just change it to `performSegue` then it works – Tj3n May 26 '17 at 09:44
  • Maybe this'll help https://stackoverflow.com/questions/5210535/passing-data-between-view-controllers – adamfowlerphoto May 26 '17 at 16:32

2 Answers2

0

You should declare a messageLabel in HistoryView. when performing segue, assign the value and that's it.

class HistoryView: UIViewController, AVCaptureMetadataOutputObjectsDelegate {
    var messageLabel: String?

}



class QRCodeScanner: UIViewController {
    func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?){   
        if segue.destination.isKind(of:HistoryView.self){
            if let vc2 = segue.destination as? HistoryView {
                vc2.messageLabel = self.messageLabel.text
            }
        }
    }
}
Willjay
  • 6,381
  • 4
  • 33
  • 58
  • First, your second if statement in the QRCodeScanner is invalid and caused an error. Second, I get the error "value of type QRScannerController has no member messageLabel" – CALVIN May 26 '17 at 09:54
  • It should be your `@IBOutlet var messageLabel:UILabel!` – Willjay May 26 '17 at 10:03
  • Yes!! I have done this and got it to execute but the text comes up blank. – CALVIN May 26 '17 at 10:18
0

I would propose you just pass the actual text to the next view controller instead of the whole previous view controller. The general problem is though that the prepareForSegue function will never be called, as the HistoryView controller is not presented via a segue, but programmatically.

To pass data to the HistoryView controller programmatically do this in the captureOutput function in the QRScannerViewController:

let vc3: HistoryView = storyboard!.instantiateViewController(withIdentifier: "View") as! HistoryView
vc3.messagetext = metadataObj.stringValue
self.present(vc3, animated: true, completion: nil)

To add a new property in the history vc:

class HistoryView: UIViewController, AVCaptureMetadataOutputObjectsDelegate {
    var messageText: String?
}

Then you can remove the prepareForSegue function completely as it is not called anyway.

bughana
  • 324
  • 5
  • 12
  • Do you assign the textHistoryText to the messageText like this: textHistory.text = messageText ? And is the text on the messageLabel set when you reach prepareForReuse? – bughana May 26 '17 at 10:20
  • Yes i have assigned the texts. i have the prepare function last. It is after the switch to the new view so the message label should be set by then. – CALVIN May 26 '17 at 10:34
  • I have set a dummy value to read out "555" in the place of the messageLabel.text. It still would not read anything. That assures me that data is not transferring to the other class. – CALVIN May 26 '17 at 10:35
  • I see. But you do reach this line in the prepareForSegue: vc2.messageText = self.messageLabel.text ? – bughana May 26 '17 at 10:37
  • How do I know If I have for sure reached that line? – CALVIN May 26 '17 at 10:52
  • Either set a breakpoint in there while running the app or add a print("messageText set to \(self.messageLabel.text)") and check in your console if that is printed when navigating to your history view – bughana May 26 '17 at 10:55
  • Yes! the code is successfully reaching the lines it just isn't reading – CALVIN May 26 '17 at 10:55
  • Hm.... one other thing you can try is to update your label whenever the value of messageText changes. You need to implement the setter of the property for that like this: var messageText: String? { didSet { self.textHistory.text = messageText } } – bughana May 26 '17 at 10:59
  • Do you mind if I send you my project and you take a look? – CALVIN May 26 '17 at 11:06
  • Go ahead, i can take a look. – bughana May 26 '17 at 11:10
  • Apparently I'm not allowed to chat yet since i just made the account LOL if you don't mind me emailing it to you I can, otherwise I'm just out of luck! – CALVIN May 26 '17 at 11:14
  • I sent it. Thanks for your help! – CALVIN May 26 '17 at 11:42