我有两个表视图。用户点击的一个和显示数据的一个。当用户单击第一个表视图中的单元格时,将对我的firebase数据库进行查询,并将查询存储在Array中。然后我通过segue传递数据。我使用了属性观察器,所以我知道变量正在设置中。通过使用断点,我能够确定我的变量在cellForRowAtIndexPath方法之前获得其值。我需要帮助在表格视图中显示数据。我不知道在哪里重新加载数据以使表格视图更新我的数据。我正在使用Swift。
编辑2:我已经解决了我的问题。我将发布我的第一个和第二个表视图,以便您可以看到我的解决方案。
FirstTableView
writeToParcel(...)
}
import UIKit
import Firebase
import FirebaseDatabase
class GenreTableViewController: UITableViewController {
let dataBase = FIRDatabase.database()
var genreArray = ["Drama","Classic,Comic/Graphic novel","Crime/Detective","Fable,Fairy tale","Fantasy","Fiction narrative", "Fiction in verse","Folklore","Historical fiction","Horror","Humour","Legend","Magical realism","Metafiction","Mystery","Mythology","Mythopoeia","Realistic fiction","Science fiction","Short story","Suspense/Thriller","Tall tale","Western,Biography","Autobiography","Essay","Narrative nonfiction/Personal narrative","Memoir","Speech","Textbook","Reference book","Self-help book","Journalism", "Religon"]
var ResultArray: [NSObject] = []
var infoArray:[AnyObject] = []
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return genreArray.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)
// Configure the cell...
cell.textLabel?.text = genreArray[indexPath.row]
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let DestViewController: ResultTableViewController = segue.destinationViewController as! ResultTableViewController
if segue.identifier == "letsGo" {
if let indexPath = self.tableView.indexPathForSelectedRow {
let tappedItem = self.genreArray[indexPath.row]
DestViewController.someString = tappedItem
}
}
}
}
为了更好的上下文和疑难解答,这里是我当前的tableView代码,它应该显示数据:
import UIKit
import Firebase
import FirebaseDatabase
class ResultTableViewController: UITableViewController {
let dataBase = FIRDatabase.database()
var SecondResultArray: [FIRDataSnapshot]! = []
var someString: String?{
didSet {
print("I AM A LARGE TEXT")
print(someString)
}
}
override func viewDidLoad() {
let bookRef = dataBase.reference().child("books")
bookRef.queryOrderedByChild("Genre")
.queryEqualToValue(someString)
.observeSingleEventOfType(.Value, withBlock:{ snapshot in
for child in snapshot.children {
self.SecondResultArray.append(child as! FIRDataSnapshot)
//print(self.ResultArray)
}
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
}
})
super.viewDidLoad()
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return SecondResultArray.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell2", forIndexPath: indexPath)
// Configure the cell...
let bookSnapShot: FIRDataSnapshot! = self.SecondResultArray[indexPath.row]
let book = bookSnapShot.value as! Dictionary<String, String>
let Author = book["Author"] as String!
let Comment = book["Comment"] as String!
let Genre = book["Genre"] as String!
let User = book["User"] as String!
let title = book["title"] as String!
cell.textLabel?.numberOfLines = 0
cell.textLabel?.lineBreakMode = NSLineBreakMode.ByWordWrapping
cell.textLabel?.text = "Author: " + Author + "\n" + "Comment: " + Comment + "\n" + "Genre: " + Genre + "\n" + "User: " + User + "\n" + "Title: " + title
let photoUrl = book["bookPhoto"], url = NSURL(string:photoUrl!), data = NSData(contentsOfURL: url!)
cell.imageView?.image = UIImage(data: data!)
return cell
}
编辑:
这是我的第一个表视图控制器。我已经尝试使用完成处理程序,但我无法正确调用它,我的查询发生在didSelectRowAtIndexPath方法的事实我受到限制。请帮忙。
import UIKit
class ResultTableViewController: UITableViewController {
var SecondResultArray: Array<NSObject> = []{
willSet(newVal){
print("The old value was \(SecondResultArray) and the new value is \(newVal)")
}
didSet(oldVal){
print("The old value was \(oldVal) and the new value is \(SecondResultArray)")
self.tableView.reloadData()
}
}
override func viewDidLoad() {
print ("I have this many elements\(SecondResultArray.count)")
super.viewDidLoad()
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return SecondResultArray.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell2", forIndexPath: indexPath)
cell.textLabel?.text = SecondResultArray[indexPath.row] as? String
return cell
}
}
答案 0 :(得分:2)
您可以在第一个prepareForSegue
的{{1}}方法中将数据注入目标viewController,然后在UIViewController
中重新加载UITableView
。如果要异步获取数据,请使用completionHandler并在completionHandler中重新加载它。这是一个例子。
viewDidAppear
答案 1 :(得分:0)
尝试更新您的闭包以包含此内容:
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
}
答案 2 :(得分:0)
编辑:
在第二次阅读时, 已经在使用完成处理程序,但我认为您没有看到它。让我纠正你的代码:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let bookRef = self.dataBase.reference().child("books")
let GenreSelector = self.genreArray[indexPath.row]
bookRef.queryOrderedByChild("Genre")
.queryEqualToValue(GenreSelector)
.observeSingleEventOfType(.Value, withBlock:{ snapshot in
// This here is your completion handler code!
// I assume it is called asynchronously once your DB is done
for child in snapshot.children {
print("Loading group \((child.key!))")
self.ResultArray.append(child as! NSObject)
}
print(self.ResultArray)
self.performSegueWithIdentifier("letsGo", sender: self)
// self.tableView.reloadData() // is this really needed
})
}
}
您定义了一个闭包,但根本没有调用它。无论如何,我都没有看到这样的理由,假设一旦数据库为您提供结果,就会调用该块。我错过了什么吗?
这已经是一个好的开始,但我认为你在这方面并没有完全掌握如何使用完成处理程序,但当然我可能错了。
我建立在user3861282的答案之上,并在my github创建了一个小型演示项目。
简而言之:您可以使用第一个表视图控制器的prepareForSegue:
方法进行所有表间通信。在那里配置第二个表视图控制器(通过其变量)。那里没有任何关闭/完成处理程序。
然后在第二个视图控制器的viewWillAppear:
方法中,开始加载(如果需要,还包括动画)。我建议像NSURLSession
那样已经定义了一个完成处理程序。因为您使用来自远程的数据,停止任何加载动画并且您很好。
如果必须在第一个表视图控制器中定义完成处理程序 ,您甚至可以在第二个表视图控制器中将其设置为var。那样你就可以移交&#34;关闭,即&#34;代码&#34;。
或者,您可以在第一个表视图控制器中启动动画和远程请求,然后在完成后performSegueWithIdentifier
启动动画和远程请求。在您的问题中,您写道,如果我理解正确,您想在第二个表视图控制器中加载。
上面的代码正确地定义了一个闭包,它需要一个完成处理程序(它也是一个闭包,所以你想要的那种双打),但你实际上从来没有在某个地方调用它。你也没有在闭包中调用完成处理程序。请参阅我的演示,了解它的工作原理。
我写的项目说明了一种方法(减去动画,没有足够的时间)。它还展示了如何定义自己的函数,期望完成处理程序,但正如我所说,框架中的标准远程连接提供了一个。
答案 3 :(得分:0)
这个怎么样:
假设您有一个从Firebase填充并存储在第一个tableViewController中的数组(myArray)。第二个tableViewController和一个连接它们的segue。
我们希望能够点击第一个tableviewController中的项目,让应用程序从Firebase(一个&#39;数据&#39;节点)中检索项目的详细数据,并在第二个tableViewController中显示详细数据
Firebase结构
some_node
child_node_0
data: some detailed data about child_node_0
child_node_1
data: some detailed data about child_node_1
在第二个tableViewContoller中:
var passedObject: AnyObject? {
didSet {
self.configView() // Update the view.
}
}
点击第一个tableView中的项目调用以下函数
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showListInSecondTable" {
if let indexPath = self.tableView.indexPathForSelectedRow {
let tappedItem = myArray[indexPath.row] as! String
let keyOfTappedItem = tappedItem.firebaseKey //child_node_0 for example
doFirebase(keyOfTappedItem)
}
}
}
然后prepareForSegue调用以下内容从firebase加载数据,当快照在块中返回时,它会填充第二个tableView中的passedObject属性
func doFirebase(firebaseKey: String) {
ref = myRootRef.childByAppendingPath("\(firebaseKey)/data")
//if we want the detailed data for child_node_0 this would resolve
// to rootRef/child_node_0/data
ref.observeSingleEventOfType(.Value, { snapshot in
let detailObjectToPass = snapshot.Value["data"] as! NSArray or string etc
let controller = (segue.destinationViewController as! UINavigationController).myViewController as! SecondViewController
controller.passedObject = detailObjectToPass
}
当然在secondController中,设置passedArray调用didSet并设置视图,并告诉tableView重新加载自己,显示传递的数组。
func configView() {
//set up the view and buttons
self.reloadData()
}
我做得非常快,所以忽略了错别字。模式是正确的,并满足问题。 (并且无需观察者启动!)
P.S。这是过度编码的方式,但我想演示流程并利用对firebase的异步调用,以便在数据在块中有效时加载第二个tableView。
答案 4 :(得分:0)
根据添加到帖子中的其他代码,问题是控制器变量超出范围。
所以这就是问题
class MyClass {
func setUpVars {
let x = 1
}
func doStuff {
print(x)
}
}
创建一个类并尝试打印x
的值let aClass = MyClass()
aClass.setUpVars
aClass.doStuff
一旦setUpVars结束,这将不会打印任何内容(概念上),'x'变量超出范围。
,而
class MyClass {
var x: Int
func setUpVars {
x = 1
}
func doStuff {
print(x)
}
}
将打印x,1的值。
所以真正的解决方案是你的viewControllers需要在你的课程(或应用程序)期间“保持活力”。
这是模式。在MasterViewController中
import UIKit
class MasterViewController: UITableViewController {
var detailViewController: DetailViewController? = nil
然后在你的MasterViewController viewDidLoad(或任何地方),创建detailViewController
override func viewDidLoad() {
super.viewDidLoad()
let controllers = split.viewControllers //this is from a splitViewController
self.detailViewController =
controllers[controllers.count-1].topViewController as? DetailViewController
}
从那里你得到它...使用prepareForSegue'将'数据'发送'到detailViewController
只是希望将此发布以供将来参考。
答案 5 :(得分:-1)
您可以使用[tableView reloadData];
重新加载TableView。