是否有从 firebase 实时数据库中获取 n 个元素的功能?

Posted

技术标签:

【中文标题】是否有从 firebase 实时数据库中获取 n 个元素的功能?【英文标题】:Is there a function for get n elements from firebase realtime database? 【发布时间】:2018-12-21 14:46:48 【问题描述】:

我的代码包含 3 个 swift 文件,用于创建动态原型 UITableViewController

1) Rent_house_Controller.swift

2) Rent_house_Cell.swift

3) Rent_house_Detail.swift

首先我将UITableViewCell的对象连接到专用的swift文件:

@IBOutlet weak var rentImage: UIImageView!

@IBOutlet weak var rentLabel: UILabel!

然后我定义了我的UITableViewController

import UIKit
import FirebaseDatabase

class Case_in_affitto: UITableViewController,
UISearchResultsUpdating, UISearchBarDelegate 

var rentImages = [String]()
var rentNames = [String]()
var webAddresses = [String]()

var searching = false
var matches = [Int]()
let searchController = UISearchController(searchResultsController: nil)

override func viewDidLoad() 
    super.viewDidLoad()

    initialize()


func initialize() 
    rentNames = ["Red Street",
                       "Green Street",
                       "Blue steet",
                       "Yellow Street",
                       "Colour Square"]

    webAddresses = ["https://website.com/rents/Red-Street",
                    "https://website.com/rents/Green-Street",
                    "https://website.com/rents/Blue-Street",
                    "https://website.com/rents/Yellow-Street",
                    "https://website.com/rents/Colour-Square"]

    rentImages = ["Red-Street.jpg",
                        "Green-Street.jpg",
                        "Blue-Street.jpg",
                        "Yellow-Street.jpg",
                        "Colour-Square.jpg"]

    tableView.estimatedRowHeight = 50
    navigationController?.navigationBar.prefersLargeTitles = true

    searchController.searchBar.delegate = self
    searchController.searchResultsUpdater = self
    searchController.obscuresBackgroundDuringPresentation = false
    searchController.searchBar.placeholder = "Cerca immobile"
    navigationItem.searchController = searchController
    definesPresentationContext = true
    let attributes = [
        NSAttributedString.Key.foregroundColor : UIColor.white,
        NSAttributedString.Key.font : UIFont.boldSystemFont(ofSize: 17)
    ]
    UIBarButtonItem.appearance(whenContainedInInstancesOf: [UISearchBar.self]).setTitleTextAttributes(attributes, for: .normal)
    UIBarButtonItem.appearance(whenContainedInInstancesOf: [UISearchBar.self]).title = "Annulla"


override func didReceiveMemoryWarning() 
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.


// MARK: Search Controller
func updateSearchResults(for searchController: UISearchController) 
    if let searchText = searchController.searchBar.text,
        !searchText.isEmpty 
        matches.removeAll()

        for index in 0..<rentNames.count 
            if rentNames[index].lowercased().contains(
                searchText.lowercased()) 
                matches.append(index)
            
        
        searching = true
     else 
        searching = false
    
    tableView.reloadData()


func searchBarCancelButtonClicked(_ searchBar: UISearchBar) 
    searching = false
    tableView.reloadData()




// MARK: - Table view data source

override func numberOfSections(in tableView: UITableView) -> Int 
    return 1


override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
    return searching ? matches.count : rentNames.count



override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 

    let cell = self.tableView.dequeueReusableCell(withIdentifier:"rentTableCell", for: indexPath) as! Case_in_Affitto_Cell

    let row = indexPath.row
    cell.rentLabel.font = UIFont.preferredFont(forTextStyle: UIFont.TextStyle.headline)
    cell.rentLabel.text = searching ? rentNames[matches[row]] : rentNames[row]
    let imageName = searching ? rentImages[matches[row]] : rentImages[row]

    cell.rentImage.image = UIImage(named: imageName)

    return cell




override func prepare(for segue: UIStoryboardSegue, sender: Any?) 
    if segue.identifier == "ShowrentDetails" 

        let detailViewController = segue.destination
            as! Case_in_Affitto_Detail

        let myIndexPath = self.tableView.indexPathForSelectedRow!
        let row = myIndexPath.row
        detailViewController.webSite =
            searching ? webAddresses[matches[row]] : webAddresses[row]
    


//Set cells height
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat 
    switch indexPath.row 
    case 0,1,2,3,4:
        return 100
    default:
        return 40
    




在这种情况下,我有一个经典的UITableViewController,它显示了我在项目中实现的值,但我需要一些不同的东西。

我想根据我在数据库中的节点数量来制作 n 个单元格。

例如:


"Sales":"",
"Rents":[

"Address":"Green_Street",
"Rooms":"2",
"Price":"70000"
,

"Address":"Red_Street",
"Rooms":"2",
"Price":"70000"
,

"Address":"Blue_Street",
"vani":"2",
"Price":"70000"
,

"Address":"Yellow_Street",
"Rooms":"2",
"Price":"70000"
,

"Address":"Colour_Square",
"Rooms":"4",
"Price":"140000"

]

换句话说,第一个问题是有一天,房子的数量会增加或减少,所以我需要制作一个函数来自动根据我的数据库的节点数填充表格。?


编辑:

我做了一些东西。 我创建了一个新的UIViewController,它从数据库中调用数据,然后我想通过UserDefaults.standard 传递所有这些数据

图像是由数据库检索的 URL 提供的,所以我还添加了键“imageURL”。

加载.swift:

if codesArray.contains("0") 
                    let userRef = rootRef.child("Rents").child("0")

                        userRef.observeSingleEvent(of: .value, with:  snapshot in
                            let userDict = snapshot.value as! [String: Any]

                            let rentAddress = userDict["Address"] as! String
                            self.address = rentAddress

                            let rentnumberOfRooms = userDict["numberOfRooms"] as! String
                            self.numberOfRooms = rentnumberOfRooms

                            let rentPrice = userDict["Price"] as! String
                            self.price = rentPrice

                            let rentimageURL = userDict["imageURL"] as! String
                            self.imageURL = rentimageURL
                            //save data on UserDefaults
                            self.savedata()
                            //loading finished
                            self.loading.stopAnimating()
                            self.performSegue(withIdentifier: "loadingfinish", sender: self)
                        )
                 else 
                    self.loading.stopAnimating()
                    let alert = UIAlertController(title: "Errore", message: "Caricamento annunci non riuscito", preferredStyle: UIAlertController.Style.alert)
                    alert.addAction(UIAlertAction(title: "ok", style: UIAlertAction.Style.default, handler: nil))
                    self.present(alert, animated: true, completion: nil)
                

如何更改此条件以加载节点“Rent”的每个子嵌套?

(请记住,我们不知道孩子有多少租金)


编辑 2:

我正在尽我所能找到这个解决方案。 我想在while cicle上使用nextObject参数来检查数据库中是否还有其他对象要存储在var address = [String]()

//setting firebase database
                        while (snapshotChildren.nextObject() as? DataSnapshot) != nil 

                            let string_child = snapshotChildren.nextObject() as? String

                            let userRef = rootRef.child("Rents").child(string_child!)

                                userRef.observeSingleEvent(of: .value, with:  snapshot in
                                    let userDict = snapshot.value as! [String: Any]

                                    self.address.append(userRef.value(forKey: "Address") as! String)

                                    let rentnumberOfRooms = userDict["numberOfRooms"] as! NSMutableArray
                                    self.numberOfRooms = rentnumberOfRooms

                                    let rentPrice = userDict["Price"] as! NSMutableArray
                                    self.price = rentPrice

                                    let rentimageURL = userDict["imageURL"] as! NSMutableArray
                                    self.imageURL = rentimageURL
                                    //avvio salvataggio dati del volontario
                                    func prepare(for segue: UIStoryboardSegue, sender: Any?) 
                                        let vc = segue.destination as! Case_in_affitto

                                        var i = 0
                                        while i==5 
                                            //this will pass the value on the address array in the Case_in_affitto.swift file
                                            vc.address.append(self.address[i])
                                            i += 1
                                        

                                    
                                )
                        
                        //loading complete
                        self.loading.stopAnimating()
                        self.performSegue(withIdentifier: "loadingfinish", sender: self)

很遗憾,这是不正确的

【问题讨论】:

【参考方案1】:

Il codice è abbastanza orribile ?(代码很可怕)

不要使用多个数组作为数据源。您已经在搜索功能中遇到了麻烦。

使用带有所有您需要的参数的自定义结构,图像由它在包中的名称表示

struct Rent 
    let address : String
    let numberOfRooms : Int
    let price : String
    let image : String

初始化器

init(address : String, numberOfRooms : Int, price : String, image : String)

免费提供。

声明一个数据源数组并从数据库中填充

var rents = [Rent]()

用相同的类型声明matches

var matches = [Rent]()

并使用此优化代码过滤对象,diacriticInsensitive 对于意大利语文本非常有用。

func updateSearchResults(for searchController: UISearchController) 
    if let searchText = searchController.searchBar.text,
        !searchText.isEmpty 
        matches = rents.filter $0.name.range(of: searchText, options: [.caseInsensitive, .diacriticInsensitive]) != nil 
        searching = true
     else 
        matches.removeAll()
        searching = false
    
    tableView.reloadData()

对应的表视图委托方法是

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
    return searching ? matches.count : rents.count



override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 

    let cell = self.tableView.dequeueReusableCell(withIdentifier:"rentTableCell", for: indexPath) as! Case_in_Affitto_Cell
    let object = searching ? matches[indexPath.row] : rents[indexPath.row]

    cell.rentLabel.font = UIFont.preferredFont(forTextStyle: UIFont.TextStyle.headline)
    cell.rentLabel.text = object.name
    cell.rentImage.image = UIImage(named: object.image)

    return cell

如果图像不应该位于捆绑包中,请将 URL 保存在数据库中,并将物理图像保存在 Documents 文件夹中。 在这种情况下声明

let imageURL : URL

在结构中并分配图像

cell.rentImage.image = UIImage(contentsOfFile: object.imageURL.path)

【讨论】:

谢谢,非常好!但是调试器说“初始化器只能在一个类型中声明” 我明白我必须将所有这些代码都放在控制器中。这里所有的错误:在函数初始化中:init(地址:字符串...)行:初始化程序只能在类型类 Case_in_affitto 行中声明:类型'Case_in_affitto'不符合协议'UISearchResultsUpdating'类'Case_in_affitto'没有初始化匹配=rents.filter 行:'Rent' 类型的值没有成员'name' cell.rentLabel.text = obkect.name 行:'Rent' 类型的值没有成员'name' cell.rentImage.image = UIImage 行:'Rent' 类型的值在函数准备搜索中没有成员 'imageURL' 吗? webAddresses[matches[row]] : webAddresses[row] 行:无法使用“Rent”类型的索引为“[String]”类型的值下标 在类外声明结构。 var rents... 替换了三个字符串数组。在initialize 中删除初始化行并用rents = [Rent(name: "Red Street", numberOfRooms: 2, price: "70000", image: "Red-Street.jpg"), Rent(name: "Blue Street", ....), Rent(name: "Green Street", ....)] 填充rents。如果图像不在应用程序包中,imageURL 是一种替代方法。 是的,现在可以使用了。但 Firebase 仍未配置。这样,单元格值仍然由 swift 文件检索。过去我使用观察者来查看已知数量的行,但这次我们不知道数据库中有多少数据。

以上是关于是否有从 firebase 实时数据库中获取 n 个元素的功能?的主要内容,如果未能解决你的问题,请参考以下文章

如何从 firebase 实时数据库中获取子值?

无法从 firebase 回收器视图中的 firebase 实时数据库中获取嵌套数据

获取firebase实时数据库中的随机条目

如何从 Firebase 实时数据库中检索/获取项目

如何根据 Angular 6 中的 Firebase 实时数据库中的键获取单个记录

如何在flutter中从firebase实时数据库中获取数据?