0

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()
    }
}
5

2 Answers 2

1

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
        
    }
}
Sign up to request clarification or add additional context in comments.

3 Comments

Thank you. I used second option, but it's failed because selectedCategoriesArr is nil when I enter ViewController, because I not yet entered FilterViewController and clicked the "Apply button". How can I fix it? i.sstatic.net/xpdP3.jpg
add an if statement to check the array you are accessing in the filter vc is empty or not
Having the same problem i.sstatic.net/FEtrI.jpg
0

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.

1 Comment

I created a method - i.sstatic.net/mOKya.png. Named segue from ViewController to the FilterViewController - filtersSegue.Added performSegue(withIdentifier: "filtersSegue", sender: self) at the end of the applyButtonClicked() method. But there is an error when I click the "Apply" button, it says " Exception: "Receiver (<CocktailDB.FilterViewController: 0x7f981c61fad0>) has no segue with identifier 'filtersSegue'" "

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.