Как разместить узлы Firebase Data в массиве - PullRequest
0 голосов
/ 15 ноября 2018

На первой странице моего приложения я использую UIViewPicker, который позволяет пользователю выбирать, какую страну он хочет выбрать.Вместо того, чтобы я жестко закодировал названия стран в UIPicker через массив (показан ниже):

var country = ["USA", "CANADA"]

Я решил, что будет лучше, если приложение получит доступ к моей базе данных Firebase, где оно сможет получить все страны, ивместо этого добавьте их в массив, и из которого будет считываться UIPicker.

Таким образом, если бы я захотел добавить больше стран, мне не пришлось бы выпускать новую версию приложения.Я мог бы просто добавить другую страну в базу данных, и приложение автоматически обновит ее.Но я не совсем уверен, как это сделать.Когда я печатаю снимок базы данных, я получаю всю базу данных, но я просто хотел бы собрать США и Канаду в массив.

Итак, вот структура моей базы данных firebase:

countries
  Canada
     states
        Alberta
        British Columbia
  USA
     states
        Alabama
        Arkansas

Вот мой текущий код:

import UIKit
import FirebaseDatabase

class ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {

    @IBOutlet weak var countryPicker: UIPickerView!

    //let country = ["USA", "Canada"] I am no longer using this hardcoded array

    var countrySelected = String()
    var action = 0 

    override func viewDidLoad() {
        super.viewDidLoad()

        //this is where I reach out to the database
        let database = Database.database().reference()
        database.child("countries").observeSingleEvent(of: .value) { (Snapshot) in
            print(Snapshot)
        }

        //add code here that takes the snapshot and appends the the array below
        var country = string()

        countrySelected = country[0]
        countryPicker.selectRow(action, inComponent: 0, animated: false)
        //print(countrySelected)
    }

    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 1
    }

    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        return country.count
    }

    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        return country[row]
    }

    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        countrySelected = country[row]
        action = country.firstIndex(of: countrySelected)!
        //print(countrySelected)
    }
}

Если бы кто-то мог помочь объяснить, это было бы здорово!

Ответы [ 2 ]

0 голосов
/ 15 ноября 2018
var countries : [Any] = []

override func viewDidLoad() {
    super.viewDidLoad()
    database.child("countries").observeSingleEvent(of: .value) { (snapshot) in
        if snapshot.exists() {
            if let dict : [String : AnyObject] = snapshot.value as? [String : AnyObject] {
                let array : [Any] = (dict as AnyObject).allValues
                self.countries = array
                // reload countryPicker data 

            } 
        } 
        else {
            // not exist in db 
        }
    }
}
0 голосов
/ 15 ноября 2018

Чтобы упростить задачу, мы можем создать некоторые структуры для представления стран и штатов.

struct Country {
    struct State {
        let country: String
        let name: String
    }

    let name: String
    let states: [State]

    static var ref: DatabaseReference {
        return Database.database().reference(withPath: "countries")
    }

    static func from(key: String, value: Any?) -> Country? {
        guard
            let value = value as? [String:[String]],
            let states = value["states"] else { return nil }

        return Country(name: key, states: states.map {
            State(country: key, name: $0)
        })
    }

    static func countries(from snapshot: DataSnapshot) -> [Country]? {
        return snapshot.snapshots.compactMap {
            Country.from(key: $0.key, value: $0.value)
        }
    }
}

И расширение DataSnapshot, чтобы предоставить нам удобный доступ к дочерним элементам снимка.

extension DataSnapshot {
    var snapshots: [DataSnapshot] {
        return children.allObjects as? [DataSnapshot] ?? []
    }
}

Затем мы создаем некоторые свойства для обработки стран - массив для их хранения и некоторые вычисляемые свойства для возврата выбранной страны и штата.

class CountryStatePickerViewController: UIViewController {

    // MARK: Outlets

    @IBOutlet weak var pickerView: UIPickerView! {
        didSet {
            loadCountries()
        }
    }

    // MARK: Properties

    private var countries = [Country]() {
        didSet {
            pickerView.reloadAllComponents()
        }
    }

    var selectedCountry: Country? {
        return country(at: pickerView.selectedRow(inComponent: 0))
    }

    var selectedState: Country.State? {
        return selectedCountry.flatMap {
            state(at: pickerView.selectedRow(inComponent: 1), in: $0)
        }
    }
}

Нам также нужно несколько методов для безопасного доступа к странам и штатам по определенному индексу, а также один для загрузки стран в первую очередь.

extension DataSnapshot {
    var snapshots: [DataSnapshot] {
        return children.allObjects as? [DataSnapshot] ?? []
    }
}

extension CountryStatePickerViewController {

    private func loadCountries() {
        Country.ref.observeSingleEvent(of: .value, with: { [weak self] in
            self?.countries = Country.countries(from: $0) ?? []
        })
    }

    private func country(at index: Int) -> Country? {
        return countries.indices.contains(index) ? countries[index] : nil
    }

    private func state(at index: Int, in country: Country) -> Country.State? {
        return country.states.indices.contains(index) ? country.states[index] : nil
    }
}

Наконец, в наших UIPickerView протокольных соответствиях массив стран заполняет источник данных. Мы можем использовать два компонента для представления стран и соответствующих им государств.

extension CountryStatePickerViewController: UIPickerViewDataSource, UIPickerViewDelegate {

    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 2
    }

    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        switch component {
        case 0:
            return countries.count
        case 1:
            return selectedCountry?.states.count ?? 0
        default:
            return 0
        }
    }

    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        switch component {
        case 0:
            return country(at: row)?.name
        case 1:
            return selectedCountry.flatMap { state(at: row, in: $0)?.name }
        default:
            return nil
        }
    }

    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {

        if component == 0 { pickerView.reloadComponent(1) }

        selectedState.flatMap { print($0.name, $0.country) }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...