【问题标题】:Swift variable still 0 after assigning it a value?Swift变量赋值后仍然为0?
【发布时间】:2016-04-21 17:14:41
【问题描述】:

在我的 viewDidLoad() 中我打印出一个函数的结果

override func viewDidLoad() {
    super.viewDidLoad()
    print("top count = \(getCurrentOrderNum())")
}

函数计算的值是这样的

func getCurrentOrderNum() -> Int{
    var orderNum = 0
    ref = Firebase(url: "urlhiddenforprivacy")
    ref.observeSingleEventOfType(.Value, withBlock: { snapshot in
        let count = snapshot.childrenCount
            orderNum = Int(count)
    })
    return orderNum
}

但它仍然打印 0?我试图将 var orderNum: Int = Int() 放在我的代码顶部,而不是放在我的 getCurrentOrderNum 函数中,但这不起作用。我知道它在我的 ref.observe 函数中得到了正确的值,因为当我运行它时......它打印出正确的值

    ref.observeSingleEventOfType(.Value, withBlock: { snapshot in
        let count = snapshot.childrenCount
            orderNum = Int(count)
            print(orderNum) //*****THIS PRINTS THE RIGHT VALUE****
    })
    return orderNum
}

【问题讨论】:

  • observeSingleEventOfType 是异步操作吗?我想是……那是你的问题。
  • 老实说,我知道这意味着什么,但是如果它是异步操作,我该如何解决?
  • 就像 Eric D 说的:observeSingleEventOfType 是一个块,似乎是异步的。因此,在您的块完成之前,您会返回。这就是为什么你总是打印 0
  • 我试图在它完成之前返回它,但该块是一个 void 函数,所以它不能返回任何东西:/
  • 丹尼尔斯的回答会起作用,但我认为你的代码可能过于复杂。请问订单号是做什么用的,什么时候需要?我问的是当您的应用程序启动时,您可以观察订单号以获得初始值。然后,每当它被任何客户端更新时,您的应用程序都会自动收到更改通知;而不是轮询它,订单号将始终准确。此外,您可能希望根据 childCount 更改您的订单号,因为有更好的解决方案 - 一旦我们有更多信息,可以在答案中解决。

标签: ios swift firebase


【解决方案1】:

在异步块实际运行之前,您正在从方法 getCurrentOrderNum() 返回 orderNum。所以返回的时候orderNum还是0,你设置的初始值。该块稍后完成。

您最好的选择可能是将方法更改为:

func getCurrentOrderNum(callback:Int->()) {
    var orderNum = 0
    ref = Firebase(url: "urlhiddenforprivacy")
    ref.observeSingleEventOfType(.Value, withBlock: { snapshot in
        let count = snapshot.childrenCount
        orderNum = Int(count)
        callback(orderNum)
    })
}

然后你会这样称呼它:

override func viewDidLoad() {
    super.viewDidLoad()
    getCurrentOrderNum { orderNum in print(orderNum) }
}

这会将getCurrentOrderNum() 方法更改为在完成检索正确值后回调到闭包。

更新:根据下面的评论,目标是做这样的事情:

func tableView(tableView: UITableView, numberOfRowsInSection section: Int)->Int { 
    return getCurrentOrderNum() 
}

这是一种异步方法:

class YourViewController : UIViewController, UITableViewDataSource {

    private var orderNumber:Int = 0
    private IBOutlet var tableView:UITableView!

    func getCurrentOrderNum(callback:Int->()) {
        ref = Firebase(url: "urlhiddenforprivacy")
        ref.observeSingleEventOfType(.Value, withBlock: { snapshot in
            let count = snapshot.childrenCount
            callback(Int(count))
        })
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        getCurrentOrderNum {
            orderNum in
            //This code runs after Firebase returns the value over the network
            self.orderNumber = orderNum  // Set our orderNumber to what came back from the request for current order number
            self.tableView.reloadData()  // Now reload the tableView so it updates with the correct number of rows
        }
    }

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {    
        return self.orderNumber // When the view first loads, this will be 0 and the table will show nothing.  After the request to Firebase returns the value, this will be set to the right number, the table view will be reloaded, and it will call this method again to get the updated number of rows to display.
    }
}

【讨论】:

  • 我从来没有用过这样的东西?如何将变量分配给函数的结果?像这样的东西 - orderNum = getCurrentOrderNum()
  • 这就是我想做的 func tableView(tableView: UITableView, numberOfRowsInSection section: Int)->Int{ return getCurrentOrderNum() }
  • @LukePatterson 由于在您想将 getCurrentOrderNum() 分配给变量的那一刻结果不可用,因此您必须将所有依赖于该结果的代码移动到回调块中,像这样: getCurrentOrderNum { orderNum in let nextOrder = orderNum + 1 // 既然我们有了 orderNum 就可以做其他事情 } 另一种选择是让你的整个应用程序在你想要获取 orderNum 的地方暂停,直到它从 Firebase 检索,它可以继续分配值。但这是一种糟糕的用户体验和不好的做法。
  • @LukePatterson 关于 tableView 数据源方法,请记住,在 table view 询问行数时,您的应用程序还不知道应该有多少行。要从 FireBase 获取 orderNum,需要通过网络发送请求并获得响应。这可能是 100 毫秒或几秒钟的等待,谁知道呢?但是表格视图需要立即响应。我会用你正在尝试做的事情来更新我的答案
【解决方案2】:

一般来说,使用 Firebase 返回函数结果可能会很棘手 - 它采用异步过程并将其压缩到同步过程中。虽然可以做到(如丹尼尔斯的好答案所示),但还有其他选择。通过查看问题中的代码,可能有几个重要的 Firebase 概念可能被忽略了。

我想展示一个利用 Firebase 强大功能的超级简单的异步解决方案。

这里有一些概念性的东西:

定义一个变量来跟踪订单号 -

var currentOrderNumber = Int

Firebase 结构

orders
  order_id_00
    order_num: 12345
  order_id_01
    order_num: 12346

在 viewDidLoad 中的订单节点上设置观察者,以在添加新订单时通知应用。这将在任何时候向节点写入订单时发生,因此所有客户端都知道当前订单号是什么:

ref.queryOnOrdersNode.childAdded { snapshot in

  if let orderNumber = snapshot.value["order_num"] as? Int {
     currentOrderNumber = orderNumber
  }

}

从那时起,无论何时打印 currentOrderNumber,它将包含实际的 currentOrderNumber。

让 Firebase 完成繁重的工作真是太酷了; Firebase 不会一遍又一遍地轮询 Firebase 以获取 currentOrderNumbers,而是会在更改时告诉您的应用当前订单号是什么。

您可以对此进行扩展以填充 tableView 并通过添加内容对其进行更新。

火力基地结构

people
  person_id_0
     name: "Bill"
  person_id_1
     name: "Larry"

以及用于填充数组并添加观察者以供将来添加的代码:

var namesArray = [String]

peopleNode.observeEventType(.ChildAdded) { snapshot in

    if let name = child.value["name"] as? String {
       namesArray.append(name)
       self.tableView.reloadData
    }  
}

和 tableView 委托方法

func tableView(tableView: UITableView, numberOfRowsInSection section: Int)->Int { 
    return peopleArray.count
}

同样,这让 Firebase 完成了繁重的工作;您不必轮询数据,因为当新人员添加到人员节点时,Firebase 会告诉您的应用程序并且 tableView 会自动更新。

您会注意到代码非常短而紧凑,因为您让 Firebase 为您完成大部分工作,让您的变量保持更新并用新数据填充表格。

(此代码中存在拼写错误,因为它是概念性的)

【讨论】:

    猜你喜欢
    • 2013-03-21
    • 2023-03-18
    • 2015-01-21
    • 1970-01-01
    • 2020-09-24
    • 2014-11-27
    • 1970-01-01
    • 2019-06-20
    相关资源
    最近更新 更多