【问题标题】:Retrieving data from Firebase takes long on Swift在 Swift 上从 Firebase 检索数据需要很长时间
【发布时间】:2017-05-05 12:50:42
【问题描述】:

我目前正在开展一个让用户租用额外空间的项目。你可以认为airbnb的克隆。在这个 iOS 应用中,我将 Firebase 用于后端即服务。

我想检索满足过滤选项的公寓,例如床位数、卧室数量、吸烟等。从逻辑上讲,我首先按时间段对所有公寓进行分组,然后获取满足过滤城市的公寓,然后我就是获取满足过滤器的单位。然后我将一一迭代所有公寓以获取它们的图像。

我的 Json 树是这样的:

filter_flats/FlatCity/FlatID
time_slots/timestamp/flatID:true
flat_images/FlatID

这是我正在尝试的:

import Foundation
import Firebase
import FirebaseStorage

protocol QuerymasterDelegate :class
{
    func getFilteredFlats(filter:FilterModel, completion: @escaping ([FilteredFlat]) -> ())
}



class Querymaster:QuerymasterDelegate
{
    var flatEndpoint = FIRFlat()

    var returningFlats = [FilteredFlat]()
    /////////////////////////////////////////////////////////////
    //MARK: This method pulls all flats with required timeslot.//
    /////////////////////////////////////////////////////////////
    internal func getFilteredFlats(filter: FilterModel, completion: @escaping ([FilteredFlat]) -> ()) {

        var zamanAraliginaUygunFlatlar = [String]()

        FIRREF.instance().getRef().child("time_slots").queryOrderedByKey().queryStarting(atValue: filter.fromDate?.toTimeStamp()).queryEnding(atValue: filter.toDate?.toTimeStamp()).observeSingleEvent(of: .value, with: { (ss) in
            for ts in ss.children.allObjects
            {
                let timeslotFlatObj = ts as! FIRDataSnapshot
                let timeslotForFlat = timeslotFlatObj.value as! [String:Bool]
                for x in timeslotForFlat
                {
                    if (x.value == true && !zamanAraliginaUygunFlatlar.contains(x.key))
                    {
                        zamanAraliginaUygunFlatlar.append(x.key)
                    }

                }
            }

            /////////////////////////////////////////////////////////
            //MARK: This method pulls all flats with filtered city.//
            /////////////////////////////////////////////////////////

            FIRREF.instance().getRef().child("filter_flats/" + filter.city!).observe(.value, with: { (ss) in

                var sehirdekiFlatler = [String:Flat]()

                for i in ss.children.allObjects
                {
                    let flt = Flat()
                    let flatObject = i as! FIRDataSnapshot
                    let mainDict = flatObject.value as! [String:Any]
                    flt.userID = (mainDict["userId"] as? String)!
                    flt.id = flatObject.key
                    flt.city = filter.city
                    flt.title = mainDict["title"] as? String
                    flt.bathroomCount = mainDict["bathroomCount"] as? Int
                    flt.bedCount = mainDict["bedCount"] as? Int
                    flt.bedroomCount = mainDict["bedroomCount"] as? Int
                    flt.internet = mainDict["internet"] as? Bool
                    flt.elevator = mainDict["elevator"] as? Bool
                    flt.heating = mainDict["heating"] as? Bool
                    flt.gateKeeper = mainDict["gateKeeper"] as?Bool
                    flt.parking = mainDict["parking"] as? Bool
                    flt.pool = mainDict["pool"] as? Bool
                    flt.smoking = mainDict["smoking"] as? Bool
                    flt.tv = mainDict["tv"] as? Bool
                    flt.flatCapacity = mainDict["capacity"] as? Int
                    flt.cooling = mainDict["cooling"] as? Bool
                    flt.price = mainDict["price"] as? Double
                    flt.washingMachine = mainDict["washingMachine"] as? Bool

                    sehirdekiFlatler[flt.id] = flt

                    if(!(zamanAraliginaUygunFlatlar).contains(flt.id))
                    {
                        if(filter.bathroomCount == nil || filter.bathroomCount! <= flt.bathroomCount!)
                        {
                            if(filter.bedCount == nil || filter.bedCount! <= flt.bedCount!)
                            {
                                if(filter.bedroomCount == nil || filter.bedroomCount! <= flt.bedroomCount!)
                                {
                                    if(filter.internet == false || filter.internet! == flt.internet!)
                                    {
                                        if(filter.elevator == false || filter.elevator! == flt.elevator!)
                                        {
                                            if(filter.heating == false || filter.heating! == flt.heating!)
                                            {
                                                if(filter.gateKeeper == false || filter.gateKeeper! == flt.gateKeeper!)
                                                {
                                                    if(filter.parking == false || filter.parking! == flt.parking!)
                                                    {
                                                        if(filter.pool == false || filter.pool! == flt.pool!)
                                                        {
                                                            if(filter.smoking! == false || filter.smoking! == flt.smoking!)
                                                            {
                                                                if(filter.tv! == false || filter.tv! == flt.tv!)
                                                                {
                                                                    if(filter.capacity == nil || filter.capacity! <= flt.flatCapacity!)
                                                                    {
                                                                        if(filter.cooling == false || filter.cooling! == flt.cooling!)
                                                                        {
                                                                            if(filter.priceFrom == nil || filter.priceFrom! <= flt.price!)
                                                                            {
                                                                                if(filter.priceTo == nil || filter.priceTo! >= flt.price!)
                                                                                {
                                                                                    if(filter.washingMachine == false || filter.washingMachine! == flt.washingMachine!)
                                                                                    {
                                                                                        let filteredFlat = FilteredFlat()
                                                                                        filteredFlat.flatCity = flt.city
                                                                                        filteredFlat.flatID = flt.id
                                                                                        filteredFlat.flatPrice = flt.price
                                                                                        filteredFlat.flatTitle = flt.title
                                                                                        filteredFlat.userID = flt.userID
                                                                                        self.returningFlats.append(filteredFlat)


                                                                                    }
                                                                                }
                                                                            }
                                                                        }
                                                                    }
                                                                }
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                ////////////////////////////////////////////////////////////////
                //MARK: This method pulls thumbnail image for returning Flats.//
                ////////////////////////////////////////////////////////////////
                if self.returningFlats.count > 0
                {
                    for a in self.returningFlats
                    {
                        FIRREF.instance().getRef().child("flat_images/" + a.flatID!).observeSingleEvent(of: .value, with: { (ss) in
                            let dict = ss.children.allObjects[0] as! FIRDataSnapshot
                            let obj = dict.value as! [String:String]
                            let flatImageDownloaded = FlatImageDownloaded(imageID: dict.key, imageDownloadURL: obj["downloadURL"]!)
                            a.flatThumbnailImage = flatImageDownloaded
                            completion(self.returningFlats)
                        })
                    }
                }
            })
        })
    }
}

标记代码This method pulls thumbnail image for returning Flats. 通常会因为在单位节点之间跳转而导致获取数据较慢。

我没有意识到我做错了什么。你能推荐更有效的方法吗?

提前致谢。

【问题讨论】:

标签: ios swift firebase firebase-realtime-database nosql


【解决方案1】:

这听起来像是您正在处理大量数据,我们不知道您当前的 UI,但这可能是帮助减少带宽和提高性能的起点。

例如,在 UI 中,当用户选择前一个按钮时会激活三个按钮。

Select City <- highlighted and ready to be tapped
Select Bedrooms <-Dimmed and not available yet
Select Internet <-Dimmed and not available yet

当用户点击选择城市时,他们会看到一个可用城市列表。这是一个简单快速的 Firebase 查询。

他们点击 Select Bedrooms 并选择 2。这里不需要真正的查询,因为它是一个介于 1 和 5 之间的数字(例如)。

他们点击选择互联网,这是一个是/否或可能是无/拨号/宽带。

现在是关键 - 结构。

City0
  name: "some city"

Flats
  flat_0
    location: "City0"
    bedrooms: "2"
    internet: "Broadband"
    filter: "City0_2_Broadband"
  flat_1
    location: "City0"
    bedrooms: "4"
    internet: "Dial up"
    filter "City0_4_Dial up"

有了这个,您可以搜索任何城市、任何数量的卧室或任何互联网作为单独的查询。

真正的强大之处在于,当您想要获取非常具体的数据时,能够执行类似 SQL 的“和”查询; 4间卧室在city0中拨号有哪些公寓

query for:  "City0_4_Dial up"

非常快速和灵活,您可以在 UI 中构建查询条件,从而限制从 Firebase 流入应用的数据量,从而使其速度非常快。

如果这离基地太远,请告诉我,我会编辑并提供另一个选项。

【讨论】:

  • 这个方法非常灵活,我的团队已经考虑过了。但是有一个关于过滤的技巧。例如,如果我们正在搜索像 City0_4_Dialup 这样的查询,我们的 UI 必须提供满足 city0_4_dialup 查询参数的单位,但如果用户没有选择卧室或互联网,我们的 UI 必须提供单位,所以我们将它们视为“无关紧要”,无论是否有互联网,卧室都会显示公寓。为了简单理解,我们的逻辑是附加的,真实的或无关紧要的,就像在 Airbnb 中一样。
  • 此外,如果用户搜索有 4 间卧室的公寓,则必须在我们的 UI 上显示拥有 5、6、7、8、9...n 间卧室的公寓。这种查询要求让我们对 Firebase 感到困惑,因为 Firebase 不像经典的关系引擎那样没有强大的查询引擎。
【解决方案2】:

Firebase 使用 NoSQL 数据库,因此典型的查询效率非常低。 据我了解,您的应用需要对数据进行大量查询,因此我猜 Firebase 本身并不是您应用的完美解决方案。

无论如何,在代码中,您可以只在Dispatch async 块中请求图像,这样可以加快处理速度。 另外,仅供参考,将图像存储在 FirebaseStorage 并将 url 存储在 FirebaseDatabase 将帮助您减少每个数据的大量成本。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-08-21
    • 2013-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多