Govind Gharmalkar
Govind Gharmalkar

Reputation: 13

Swift global Variables Not Updating

I've have been searching for this answer for days. Whenever i try to instantiate a new viewcontroller called "Govind" I get a SIGARBT error. The reason why I get a SIGARBT error is because in the view controller called I use the variables; yourVariable, ASIN, VariationImages, to find specific nodes in my database. The values for yourVariable, ASIN, and VariationImages do not change, when I set them equal to the values from firebase. The values from firebase are not nil. Here's my code

 import UIKit
    import Firebase
    import FirebaseDatabase
    var yourVariable = ""
    var ProductsNumber = 100
    var ASIN = ""
    var Weblink = ""
    var VariationImages = 5

    class Initial: UIViewController, UICollectionViewDataSource, 
    UICollectionViewDelegate {
    @IBOutlet weak var FrontPageCollectionView: UICollectionView!

    var UIFrame = UIScreen.main.bounds
    var ref: DatabaseReference!
    var DatabaseHandle = nil as DatabaseHandle!

    override func viewDidLoad() {
        super.viewDidLoad()
        ref = Database.database().reference()

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

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 3
    }

    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        self.DatabaseHandle = ref.child("Frontpage").child(String(indexPath.row)).observe(.value, with: { (TheCategory) in
            yourVariable = TheCategory.childSnapshot(forPath: "Category").value as! String
            ASIN = TheCategory.childSnapshot(forPath: "ASIN").value as! String
        self.DatabaseHandle = self.ref.child(TheCategory.childSnapshot(forPath: "Category").value as! String).child(TheCategory.childSnapshot(forPath: "ASIN").value as! String).child("VariationImages").observe(.value, with: { (NumberOfVariationImages) in
            VariationImages = Int(NumberOfVariationImages.childrenCount)
            })
        })
        CallGovind()
    }

    func CallGovind() {
        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        let controller = storyboard.instantiateViewController(withIdentifier: "Govind")
        controller.modalPresentationStyle = .popover
        self.present(controller, animated: true, completion: nil)
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
    {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "FrontpageCell", for: indexPath) as! myCell
        self.DatabaseHandle = ref.child("Frontpage").child(String(indexPath.row)).child("Thumbnail").observe(.value, with: { (snapshot) in
            cell.FrontpageImages.sd_setImage(with: URL(string: snapshot.value as! String), placeholderImage: #imageLiteral(resourceName: "Menu"), options: [.continueInBackground, .progressiveDownload])
        })
        cell.FrontpageImages.contentMode = .scaleAspectFill
        cell.FrontpageImages.layer.cornerRadius = 5
        cell.FrontpageImages.clipsToBounds = true
        return cell
    }

    }
    /*
    // MARK: - Navigation

    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        // Get the new view controller using segue.destinationViewController.
        // Pass the selected object to the new view controller.
    }
    */

    }

//Here's where the data goes into the second view controller

    import UIKit
    import Firebase
    import FirebaseDatabase


    class Testing: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {
    var ref: DatabaseReference!
    var DatabaseHandle = nil as DatabaseHandle!

    override func viewDidLoad() {
        super.viewDidLoad()

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

    //Populate view
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
    {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cells", for: indexPath) as! myCell
        self.DatabaseHandle = ref.child(yourVariable).child(ASIN).child("VariationImages").child(String(indexPath.row)).observe(.value, with: { (snapshot) in
           cell.myImageViews.sd_setImage(with: URL(string: snapshot.value as! String), placeholderImage: #imageLiteral(resourceName: "Menu"), options: [.continueInBackground, .progressiveDownload])


          })
        return cell
}

Everywhere where the DataBaseHandle is, produces an error because it is an empty string because the variables have not updated

Upvotes: 0

Views: 2329

Answers (2)

Jaydeep Vyas
Jaydeep Vyas

Reputation: 4470

AS ryantxr stated callGovind inside the closure and also good way to share variable among all the classes is singleTon.

As per my knowledge you have to create SingleTon class to manage this type variable like create seperate singleton file

import Foundation
/**
 * Created by Jaydeep on 13-Feb-17.
 */

public class Singleton
{
    var yourVariable : String = ""
    static let shared = Singleton()
    private init()
    {
    }
}

Usage

Singleton.shared.yourVariable = "xyz"

You can access singleTon class object anywhere and always you get last updated value.

Upvotes: 2

ryantxr
ryantxr

Reputation: 4219

Most likely your invocation of function CallGovind() is getting executed before the completion handlers are done. This means your other view controller is called before the variables are set.

... .observe(.value, with: { (TheCategory) in
    // Code in here will get executed asynchronously
    // and likely will get called later
    // Since you set variables in here, and they
    // are not set by the time you call the other 
    // view controller.
}

CallGovind()  // gets called BEFORE above code

One possible solution is to make sure that the other view controller is called after the completion blocks are done.

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    self.DatabaseHandle = ref.child("Frontpage").child(String(indexPath.row)).observe(.value, with: { (TheCategory) in
        yourVariable = TheCategory.childSnapshot(forPath: "Category").value as! String
        ASIN = TheCategory.childSnapshot(forPath: "ASIN").value as! String
        self.DatabaseHandle = self.ref.child(TheCategory.childSnapshot(forPath: "Category").value as! String).child(TheCategory.childSnapshot(forPath: "ASIN").value as! String).child("VariationImages").observe(.value, with: { (NumberOfVariationImages) in
            VariationImages = Int(NumberOfVariationImages.childrenCount)
            // Call other controller here so that the variables
            // are set
            DispatchQueue.main.async {
                CallGovind()
            }
        })
    })

}

Upvotes: 1

Related Questions