Чтение из массива даже с проблемой DispatchGroup - PullRequest
0 голосов
/ 16 января 2020

У меня возникла проблема, когда я беру строки из коллекции Firebase и отображаю их в виде коллекции.

В основном я считаю, что функция Firebase не выполняется достаточно быстро для программы, поэтому я помещаю ее в DispatchGroup, которая также не решила проблему

 //arrays of names and descriptions
    var names:[String] = []
    var descriptions: [String] = []

Вот функция firebase, которая работает при извлечении имен и описаний из firebase

func firebase()
{
    //connection to firebase for the names and descriptions
    let db = Firestore.firestore()

    db.collection(test).getDocuments { (snapshot, err) in

        if let err = err {

            print("Error getting documents: \(err)")
        } else {
            for document in snapshot!.documents {
                let name = document.get("Name") as! String
                let description = document.get("Description") as! String
                //Add names and descriptions to the arrays
                self.names.append(name)
                self.descriptions.append(description)
            }
            for x in self.names{
                print(x)
            }
            for y in self.descriptions{
                print(y)
            }
        }
    }
}

Вот функция ViewDidLoad: она отлично работает когда я не пытаюсь напечатать имена [0]

override func viewDidLoad() {
    super.viewDidLoad()
    let myGroup = DispatchGroup()
    myGroup.enter()
    firebase()

    // When your task completes
    myGroup.leave()
    myGroup.notify(queue: DispatchQueue.main) {
        // do your remaining work
        print(self.names[1])
        self.setupBottomControls()
        self.setupTopControls()
        self.setupButton()

        self.setupImages()

        self.collectionView?.backgroundColor = .white
        self.collectionView?.register(PageCell.self, forCellWithReuseIdentifier: "cellId")

        self.collectionView?.isPagingEnabled = true
    }
}

Я получаю сообщение об ошибке:

Fatal error: Index out of range

Ответы [ 3 ]

2 голосов
/ 16 января 2020

Вы неправильно используете DispatchGroup. Это неуместно в этом случае.

Просто добавьте обработчик завершения

func firebase(completion: @escaping () -> Void)
{
    //connection to firebase for the names and descriptions
    let db = Firestore.firestore()

    db.collection(test).getDocuments { (snapshot, err) in

        if let err = err {

            print("Error getting documents: \(err)")
        } else {
            for document in snapshot!.documents {
                let name = document.get("Name") as! String
                let description = document.get("Description") as! String
                //Add names and descriptions to the arrays
                self.names.append(name)
                self.descriptions.append(description)
            }
            for x in self.names{
                print(x)
            }
            for y in self.descriptions{
                print(y)
            }
            completion()
        }
    }
}

И используйте его

override func viewDidLoad() {
    super.viewDidLoad()

    firebase() { [unowned self] in
         DispatchQueue.main.async {
            // do your remaining work
            print(self.names[1])
            self.setupBottomControls()
            self.setupTopControls()
            self.setupButton()

            self.setupImages()

            self.collectionView?.backgroundColor = .white
            self.collectionView?.register(PageCell.self, forCellWithReuseIdentifier: "cellId")

            self.collectionView?.isPagingEnabled = true
        }
    }
}
0 голосов
/ 16 января 2020

Единственное место, где я могу увидеть потенциал для исключения вне границ, это

print(self.names[1])

Скорее всего, вы можете установить точку останова и вручную проверить массив имен (po self.names)

У вас неправильный подход, но я собираюсь исправить ваш код для справки. ТОГДА подскажу, что вы должны делать

В любом случае, чтобы вы могли подумать о том, почему это происходит, проблема заключается в следующих строках кода:

    myGroup.enter()
    firebase()

    // When your task completes
    myGroup.leave()

Ваш комментарий неверный. У созданной вами забавной базы Firebase c есть некоторый асин c код - так что он завершится sh и почти сразу перейдет к myGroup.leave() fun c. Вы хотите уйти, когда завершится асин c код. Самый стандартный способ выполнения sh - это, безусловно, просто использовать обработчик завершения вместо DispatchGroup (vadian опубликовал это решение, пока я писал). Но просто чтобы проиллюстрировать вашу ошибку:

func firebase(dispatchGroup: DispatchGroup) {
    ...
    // this is an async call vv
    db.collection(test).getDocuments { (snapshot, err) in
        ... // all the code
        // NOW that you're done, leave the group
        dispatchGroup.leave()
    }
}

, тогда вы можете передать ее как:

    myGroup.enter()
    firebase(dispatchGroup: myGroup)

Однако ... вам не следует ждать, пока этот ответ выполнит basi c код компоновки. Я не уверен, какой из этих методов на самом деле использует self.names или self.descriptions, но любые из этих строк, которые не могут быть просто выполнены сразу:

override func viewDidLoad() {
    super.viewDidLoad()

    firebase()

    self.setupBottomControls()
    self.setupTopControls()
    self.setupButton()

    // im going to pretend this function relies on the self.names/self.descriptions
    // self.setupImages()

    self.collectionView?.backgroundColor = .white
    self.collectionView?.register(PageCell.self, forCellWithReuseIdentifier: "cellId")

    self.collectionView?.isPagingEnabled = true

}

, затем один раз функция firebase хорошо заканчивается, просто вызовите ту, которая опирается на данные ...

func firebase()
{
    //connection to firebase for the names and descriptions
    let db = Firestore.firestore()
    db.collection(test).getDocuments { (snapshot, err) in
        // code
        // now that im done and I have the data...
        DispatchQueue.main.async {
            self.setupImages()
            // self.collectionView.reloadData() // also maybe this??
        }
    }
}

вам не нужно делать все в viewDidLoad, просто сделайте это, когда будете готовы.

0 голосов
/ 16 января 2020

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

Попробуйте это:

override func viewDidLoad() {
        super.viewDidLoad()
        firebase()
    }

    func firebase() {
        let myGroup = DispatchGroup()
        myGroup.enter()

        Firestore.firestore().collection(test).getDocuments { (snapshot, err) in
            if let err = err {
                print("Error getting documents: \(err)")
            } else {
                for document in snapshot!.documents {
                    let name = document.get("Name") as! String
                    let description = document.get("Description") as! String
                    //Add names and descriptions to the arrays
                    self.names.append(name)
                    self.descriptions.append(description)
                }
            }
            myGroup.leave()
        }

        myGroup.notify(queue: DispatchQueue.main) {
            setupView()
        }
    }

    func setupView() {
        setupBottomControls()
        setupTopControls()
        setupButton()
        setupImages()

        collectionView?.backgroundColor = .white
        collectionView?.register(PageCell.self, forCellWithReuseIdentifier: "cellId")

        collectionView?.isPagingEnabled = true
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...