Ios 如何加快从Firebase Firestore获取数据的速度?

Ios 如何加快从Firebase Firestore获取数据的速度?,ios,swift,firebase,google-cloud-firestore,Ios,Swift,Firebase,Google Cloud Firestore,我是编程和iOS开发方面的新手。我正在尝试使用Firebase中的Firestore数据库制作一个应用程序。我不知道这是否正常,但当我试图从firestore数据库获取数据时,它对我来说似乎太长了。我不知道我是否犯了错误 这是我从firestore获取所有城市数据的代码 class CityKM { var name : String var coordinate : GeoPoint init (name: String , coordinate: GeoPoint

我是编程和iOS开发方面的新手。我正在尝试使用Firebase中的Firestore数据库制作一个应用程序。我不知道这是否正常,但当我试图从firestore数据库获取数据时,它对我来说似乎太长了。我不知道我是否犯了错误

这是我从firestore获取所有城市数据的代码

class CityKM {
    var name : String
    var coordinate : GeoPoint

    init (name: String , coordinate: GeoPoint ) {
        self.name = name
        self.coordinate = coordinate
    }

    init (dictionary: [String:Any]) {
        // this init will be used if we get data from firebase observation to construct an event object

        name = dictionary["name"] as! String
        coordinate = dictionary["coordinate"] as! GeoPoint
    }

    static func getAllCitiesDataFromFirestore (completion: @escaping ( [CityKM]? )->Void) {
        // to retrieve all cities data from Firebase database by one read only, not using realtime fetching listener

        let startTime = CFAbsoluteTimeGetCurrent() // to track time consumption of this method

        FirestoreCollectionReference.cities.reference().getDocuments { (snapshot, error) in
            if let error = error {
                print("Failed to retrieve all cities data: \(error.localizedDescription)")
            } else {
                print("Sucessfully get all cities data from firestore")

                guard let documentsSnapshot = snapshot, !documentsSnapshot.isEmpty else {
                    completion(nil)
                    return
                }

                let citiesDocuments = documentsSnapshot.documents
                var cityArray = [CityKM]()

                for document in citiesDocuments {
                    guard let cityName = document.data()["name"] as? String,
                          let cityCoordinate = document.data()["coordinate"] as? GeoPoint else {return}

                    let theCity = CityKM(name: cityName, coordinate: cityCoordinate)
                    cityArray.append(theCity)
                }

                completion(cityArray)

                let timeElapsed = CFAbsoluteTimeGetCurrent() - startTime // to track time consumption of this method
                print("Time needed to get all cities data from Firestore : \(timeElapsed) s.") // to track time consumption of this method

            }
        }
    }


}



extension CityKM {

    // MARK: - User Helper Methods
    func toDictionary() -> [String:Any]{
        return [
            "name" : name,
            "coordinate" : coordinate
        ]
    }


}
参考:

import Foundation
import FirebaseFirestore
import Firebase

enum FirestoreCollectionReference {
    case users
    case events
    case cities

    private var path : String {
        switch self {
        case .users : return "users"
        case .events : return "events"
        case .cities : return "cities"
        }
    }

    func reference () -> CollectionReference {
        return Firestore.firestore().collection(path)
    }
}
我在
CityKM
类中使用
getAllCitiesDataFromFirestore
方法来获取存储在firestore中的城市数据

class CityKM {
    var name : String
    var coordinate : GeoPoint

    init (name: String , coordinate: GeoPoint ) {
        self.name = name
        self.coordinate = coordinate
    }

    init (dictionary: [String:Any]) {
        // this init will be used if we get data from firebase observation to construct an event object

        name = dictionary["name"] as! String
        coordinate = dictionary["coordinate"] as! GeoPoint
    }

    static func getAllCitiesDataFromFirestore (completion: @escaping ( [CityKM]? )->Void) {
        // to retrieve all cities data from Firebase database by one read only, not using realtime fetching listener

        let startTime = CFAbsoluteTimeGetCurrent() // to track time consumption of this method

        FirestoreCollectionReference.cities.reference().getDocuments { (snapshot, error) in
            if let error = error {
                print("Failed to retrieve all cities data: \(error.localizedDescription)")
            } else {
                print("Sucessfully get all cities data from firestore")

                guard let documentsSnapshot = snapshot, !documentsSnapshot.isEmpty else {
                    completion(nil)
                    return
                }

                let citiesDocuments = documentsSnapshot.documents
                var cityArray = [CityKM]()

                for document in citiesDocuments {
                    guard let cityName = document.data()["name"] as? String,
                          let cityCoordinate = document.data()["coordinate"] as? GeoPoint else {return}

                    let theCity = CityKM(name: cityName, coordinate: cityCoordinate)
                    cityArray.append(theCity)
                }

                completion(cityArray)

                let timeElapsed = CFAbsoluteTimeGetCurrent() - startTime // to track time consumption of this method
                print("Time needed to get all cities data from Firestore : \(timeElapsed) s.") // to track time consumption of this method

            }
        }
    }


}



extension CityKM {

    // MARK: - User Helper Methods
    func toDictionary() -> [String:Any]{
        return [
            "name" : name,
            "coordinate" : coordinate
        ]
    }


}
从我的调试区域,它被打印出来

“从Firestore获取所有城市数据所需的时间:1.87678903秒。”

有可能使它更快吗?1.8秒正常吗?我是否在代码中犯了错误,导致请求数据花费的时间太长?我希望我能在一秒钟内提出请求


我不认为互联网速度是个问题,因为我可以在youtube上打开视频而不需要缓冲,这样的性能听起来比我看到的要差一些,但没有什么过分。从云端加载数据只需花费时间。隐藏延迟的一种快速方法是利用Firebase的内置缓存

调用
getDocuments
时,Firebase客户端需要在服务器上检查文档的值,然后才能调用代码,然后向用户显示该值。如前所述:没有办法加快代码的读取速度,因此用户在看到文档之前至少需要1.8秒


如果改为使用
addSnapshotListener
,Firebase客户端可能会立即使用其本地缓存中的值调用代码,然后在服务器上的数据发生更新时重新调用代码

我看到了差不多相同的响应时间。这并不过分。如果您立即需要它,您可以考虑在需要它之前在后台异步下载它。此外,如果您不需要一次点击中的所有数据,您可以使用
.limit(to:x)
并在需要时获取更多数据。非常感谢您坦率的回答:),我是编程新手,当然我也是Firebase新手。似乎有两种方法可以从Firebase获取数据,一种是实时更新addSnapshotListener,另一种是使用getDocuments。但我无法区分何时必须使用其中一种?我的意思是实时更新看起来很神奇,那么为什么我必须使用getDocuments呢?你有文章来区分这两个吗?提前感谢Frank:)旧的实时数据库大力推广了实时更新。事实上,它相当于
getDocuments()
实际上是一个快速侦听等待停止侦听序列。许多开发人员发现,这种方法比更常见的
get
方法更难使用。在Firestore中,
get
listen
都是一等公民。你想用哪一种都行。但是,由于
get()
只给您一次结果,它通常必须首先与服务器进行检查,以确保您没有从缓存中看到过时的数据。我有一个包含大约5000个文档的集合,使用snapshotListener比getdocuments更快地返回结果。我的问题是,如果同时更新多个文档,我的tableview会冻结一段时间,这会让UX变得更糟。