使用NotificationCenter Observer处理asynchronous请求

这个问题也有类似的问题,所以我很抱歉,但是没有人能够帮助我。

我正努力将这个asynchronous请求的值从完成处理程序返回给Firebase。 我从Firebase中检索的值是一个数组,它确实存在。 但

以下是我向Firebase发出请求的function:

class SearchManager { var searchResults = [String]() var listOfMosaics = [String]() // Retrieves company list from Firebase func getMosaicTitles(completionHandler: @escaping (_ mosaics: [String]) -> ()) { Database.database().reference().child("mosaics").observeSingleEvent(of: .value, with: { (snapshot) in guard let allMosaics = snapshot.value as? [String] else { print("unable to unwrapp datasnapshot") return } completionHandler(allMosaics) }) } // resets search results array func resetSearch() { searchResults = [] } // takes list of all mosaics and filters based on search text func filterAllMosaics(searchText: String) { searchResults = listOfMosaics.filter { $0.contains(searchText) } } } 

在AppDelegate中,我把它称为这个发布通知:

  let searchManager = SearchManager() func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { makeRootViewLaunchScreen() FirebaseApp.configure() searchManager.getMosaicTitles { (results) in self.searchManager.listOfMosaics = results NotificationCenter.default.post(name: NSNotification.Name("mosaicsReturned"), object: nil) self.stopDisplayingLaunchScreen() } // Adds border to bottom of the nav bar UINavigationBar.appearance().shadowImage = UIImage.imageWithColor(color: UIColor(red:0.00, green:0.87, blue:0.39, alpha:1.0)) // Override point for customization after application launch. return true } func makeRootViewLaunchScreen() { let mainStoryboard: UIStoryboard = UIStoryboard(name: "LaunchScreen", bundle: nil) let viewController = mainStoryboard.instantiateViewController(withIdentifier: "launchScreen") UIApplication.shared.keyWindow?.rootViewController = viewController } // reassigns root view after Firebase request complete func stopDisplayingLaunchScreen() { let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil) let viewController = mainStoryboard.instantiateViewController(withIdentifier: "centralViewController") UIApplication.shared.keyWindow?.rootViewController = viewController } 

在支持tableView的viewController的viewDidLoad中,使用检索的数组填充它,我添加了一个Notification Observer。

  var listOfMosaics = [String]() var searchResults = [String]() { didSet { tableView.reloadData() } } override func viewDidLoad() { super.viewDidLoad() listOfMosaics = searchManager.listOfMosaics configureSearchBar() configureSearchBarTextField() self.tableView.separatorColor = UIColor(red:0.00, green:0.87, blue:0.39, alpha:1.0) NotificationCenter.default.addObserver(self, selector: #selector(updateListOfMosaics), name: NSNotification.Name("mosaicsReturned"), object: nil) } @objc func updateListOfMosaics(notification: Notification) { listOfMosaics = searchManager.listOfMosaics } 

但是,当我调用下面的代码不起作用的数组打印为空,因此它不会更新我的tableView。

 extension SearchResultsTableViewController: UISearchBarDelegate { func searchBarSearchButtonClicked(_ searchBar: UISearchBar) { searchManager.resetSearch() searchManager.filterAllMosaics(searchText: searchBar.text!) tableView.reloadData() print(listOfMosaics) print(searchResults) } } 

先进的谢谢您的帮助。

这现在应该适合你。 我想你没有把你的AppDelegate的SearchManager实例传递给你的ViewController。 我猜你在ViewController中创build了一个新的SearchManager实例,它有一个空的数组。

searchpipe理器:

 class SearchManager { var searchResults = [String]() var listOfMosaics = [String]() func getMosaicTitles(completionHandler: @escaping (_ mosaics: [String]) -> ()) { Database.database().reference().child("mosaics").observeSingleEvent(of: .value, with: { (snapshot) in guard let allMosaics = snapshot.value as? [String] else { print("unable to unwrapp datasnapshot") completionHandler([]) // <- You should include this too. return } completionHandler(allMosaics) }) } func resetSearch() { searchResults = [] } func filterAllMosaics(searchText: String) { searchResults = listOfMosaics.filter { $0.contains(searchText) } } } 

视图控制器:

 class TableViewController: UITableViewController { var searchManager: SearchManager? var listOfMosaics = [String]() var searchResults = [String]() { didSet { tableView.reloadData() } } override func viewDidLoad() { super.viewDidLoad() guard let searchManager = searchManager else { return } listOfMosaics = searchManager.listOfMosaics print("List of mosaics: \(listOfMosaics)") } override func numberOfSections(in tableView: UITableView) -> Int { return 0 } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return 0 } } 

AppDelegate中:

 class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? let searchManager = SearchManager() func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { makeRootViewLaunchScreen() FirebaseApp.configure() searchManager.getMosaicTitles { results in self.searchManager.listOfMosaics = results self.stopDisplayingLaunchScreen() } return true } func makeRootViewLaunchScreen() { let mainStoryboard: UIStoryboard = UIStoryboard(name: "LaunchScreen", bundle: nil) let viewController = mainStoryboard.instantiateViewController(withIdentifier: "launchScreen") window?.rootViewController = viewController window?.makeKeyAndVisible() } func stopDisplayingLaunchScreen() { let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil) guard let viewController = mainStoryboard.instantiateViewController(withIdentifier: "centralViewController") as? TableViewController else { return } let navigationController = UINavigationController(rootViewController: viewController) viewController.searchManager = searchManager window?.rootViewController = navigationController window?.makeKeyAndVisible() } } 

正如@TNguyen在他的评论中所说,听起来你不是在等待asynchronous函数getMosaicTitles()来完成。

您可能希望在调用运行时禁用search栏button,并在调用完成后从完成处理程序启用它。 然后,用户将无法点击searchbutton,直到结果加载完成。

您可以在后台线程中从数据库中获取数据,并添加一个完成块,以便在获取更新后的内容之后才能重新加载tableView。