user13935654
user13935654

Reputation: 9

Swift - access array from another ViewController

In FilterViewController I have "applyButtonClicked" method that fires up on button click. In this method I fill in and get "selectedCtgsArr" array that I want to use in ViewController file.

How can I copy the value of the selectedCtgsArr from the FilterViewController to the selectedCategoriesArr from the ViewController when selectedCtgsArr array is already filled (applyButtonClicked method fired up)?

FilterViewController:

class FilterViewController: UIViewController {
    
        var categories = [Category]()
        
        var output = [[String : Any]]()
        
        var selectedCtgsArr = [String]()
        
        @IBOutlet weak var tableView: UITableView!
        @IBOutlet weak var applyButton: UIButton!
        
        override func viewDidLoad() {
            super.viewDidLoad()
            getCategories()
        }
    
    @IBAction func applyButtonClicked(_ sender: UIButton) {
        
        var selectedCatgry = [String]()
        
        for i in 0..<output.count {
            let rowVal = output[i]
            if rowVal["status"] as! String == "1"{
                selectedCatgry.append(rowVal["name"] as! String)
            }
        }
        selectedCtgsArr = selectedCatgry
        print(selectedCtgsArr) // copy this array 
    }
    
    func getCategories() {
        let url = URL(string: "https://www.thecocktaildb.com/api/json/v1/1/list.php?c=list")
        
        URLSession.shared.dataTask(with: url!) { (data, response, error) in
            
            if error == nil {
                do {
                    self.categories = try JSONDecoder().decode(Categories.self, from: data!).drinks
                    
                    for i in 0..<self.categories.count {
                        self.output.append(["name":self.categories[i].strCategory, "status":"1"])
                    }
                    
                    DispatchQueue.main.async {
                        self.tableView.reloadData()
                    }
                } catch {
                    print(error)
                }
            }
        }.resume()
    }
}

ViewController:

class ViewController: UIViewController {
    
    var drinks = [Drink]()
    var categories = [OneCategory]()
    
    @IBOutlet weak var tableView: UITableView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        loadAllCategories()

        var selectedCategoriesArr: [String] = [] // copy here
        
    }
    
    func loadAllCategories() {
        let url = URL(string: "https://www.thecocktaildb.com/api/json/v1/1/list.php?c=list")
        
        URLSession.shared.dataTask(with: url!) { (data, response, error) in
            
            if let error = error {
                print(error)
                return
            }
            
            do {
                let result = try JSONSerialization.jsonObject(with: data!) as! [String:Any]
                let categoryNames = (result["drinks"] as! [[String:String]]).map{$0["strCategory"]!}
                let group = DispatchGroup()
                
                for category in categoryNames {
                    let categoryURLString = "https://www.thecocktaildb.com/api/json/v1/1/filter.php?c=\(category)"
                        .addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!
                    let categoryURL = URL(string: categoryURLString)!
                    
                    group.enter()
                    let categoryTask = URLSession.shared.dataTask(with: categoryURL) { (categoryData, _, categoryError) in
                        
                        defer {
                            group.leave()
                        }
                        
                        if let categoryError = categoryError {
                            print(categoryError)
                            return
                        }
                        
                        do {
                            let drinks = try JSONDecoder().decode(Response.self, from: categoryData!).drinks
                            self.categories.append(OneCategory(name: category, drinks: drinks))
                        } catch {
                            print(error)
                        }
                    }
                    categoryTask.resume()
                }
                
                group.notify(queue: .main) {
                    self.tableView.reloadData()
                }
                
            } catch {
                print(error)
            }
        }.resume()
    }
}

Upvotes: 0

Views: 958

Answers (2)

Hani Elmalky
Hani Elmalky

Reputation: 21

There are three ways to do so:

1- Using programatic segue using function prepare for segue if there's connection between the two view controllers.

2- Using Protocols in the filter view controller

protocol FilterViewProtocol: AnyObject {
    var selectedCatgry: [String] {get}
}

class FilterViewController: UIViewController {
    
    var categories = [Category]()
    
    var output = [[String : Any]]()
    
    var selectedCtgsArr = [String]()
    
    var selectedCatgry: [String] {
        return selectedCtgsArr
    }
}

in the view controller

class ViewController: UIViewController {
    var filter: FilterViewProtocol!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        loadAllCategories()
        
        var selectedCategoriesArr: [String] = filter.selectedCatgry
        
    }
}

3- using static variable however this method is not recommended in filter view controller

class FilterViewController: UIViewController {
    
    var categories = [Category]()
    
    var output = [[String : Any]]()
    
    var static selectedCtgsArr = [String]()
}

in view controller

class ViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        loadAllCategories()
        
        var selectedCategoriesArr: [String] = FilterViewController.selectedCtgsArr
        
    }
}

Upvotes: 1

Max
Max

Reputation: 22325

According to Apple's guide on Using Segues

The prepareForSegue:sender: method of the source view controller lets you pass data from the source view controller to the destination view controller. The UIStoryboardSegue object passed to the method contains a reference to the destination view controller along with other segue-related information.

What this looks like is usually a pattern like this

public override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if let destination = segue.destination as? TypeOfViewControllerBeingShown {
        destination.someMethodAcceptingData(dataToShare)
    }
}

you pass whatever data you want and the destination view controller does whatever it needs to with it. All of this happens before the destination view controller appears on screen so it can use this information to any setup/configuration needed.

Upvotes: 0

Related Questions