我在表格视图中选择了一个地点类别列表,但在 segue 中它只发送一个

Posted

技术标签:

【中文标题】我在表格视图中选择了一个地点类别列表,但在 segue 中它只发送一个【英文标题】:I select a list of place categories in a tableview but in the segue it only sends one 【发布时间】:2017-10-30 09:39:39 【问题描述】:

我有一个带有 tableView 的 UiViewController,这个 tableView 有一个我可以选择的地方 (googlePlaces) 列表(例如餐馆、电影院、酒吧),然后点击一个按钮在我期望的下一个控制器中继续查看我选择的类型的地点列表;问题是它不会为所有选定的类别留下位置,例如,如果我选择了电影院、酒吧和餐厅,一次它只显示餐厅,另一次只显示电影院,以完全随意的方式。这是我的准备

override func prepare(for segue: UIStoryboardSegue, sender: Any?) 

        if segue.identifier == nearbySearchSegueIdentifier 
            let selectedCategories: [QCategoryy] = tableView.indexPathsForSelectedRows?.map( (indexPath) -> QCategoryy in
                return list[indexPath.row] ) ?? []

            if let selectedRows = tableView.indexPathsForSelectedRows 

                if let vc : CourseClass2 = segue.destination as? CourseClass2 
                vc.categories = selectedCategories

            
        
    

这是下一个视图控制器

import UIKit
import CoreLocation
import Social
import AVFoundation


private let resueIdentifier = "MyTableViewCell"


extension UIViewController 
    func present(viewController : UIViewController, completion : (() -> ())? = nil )
        if let presented = self.presentedViewController 
            presented.dismiss(animated: true, completion: 
                self.present(viewController, animated: true, completion: completion)
            )
         else 
            self.present(viewController, animated: true, completion: completion)
        
    



class CourseClass2: UIViewController, UITableViewDelegate, UITableViewDataSource 





    @IBOutlet weak var tableView: UITableView!

    var locationManager:CLLocationManager?
    let minimumSpacing : CGFloat = 15 //CGFloat(MAXFLOAT)
    let cellWidth: CGFloat = 250
    let radius = 5000 // 5km
    var categories: [QCategoryy?]? = []
    var currentLocation : CLLocationCoordinate2D?
    var places: [QPlace] = []
    var isLoading = false
    var response : QNearbyPlacesResponse?
    var rows = 0
    var numberPlaces = 0

    override func viewDidLoad() 
        super.viewDidLoad()
        for category in categories! 

         title = category?.name
    
        tableView.dataSource = self
        tableView.delegate = self
        numberPlaces = HomeClass.globalLimit
    


    override func viewWillAppear(_ animated: Bool) 
        super.viewWillAppear(animated)

        determineMyCurrentLocation()
    

    override func viewWillDisappear(_ animated: Bool) 
        super.viewWillDisappear(animated)
    



    override func viewDidAppear(_ animated: Bool) 
        super.viewDidAppear(animated)

         rows = 0
        tableView.reloadData()
         for category in categories! 

        category?.markView()
    





    @IBAction func refreshTapped(_ sender: Any) 

         rows = 0
        print("numberOfRows Call", self.numberPlaces)
        tableView.reloadData()
    




    func canLoadMore() -> Bool 
        if isLoading 
            return false
        

        if let response = self.response 
            if (!response.canLoadMore()) 
                return false
            
        

        return true
    

    func loadPlaces(_ force:Bool) 

        if !force 
            if !canLoadMore() 
                return
            
        

        print("load more")
        isLoading = true
         for category in categories! 

        NearbyPlaces.getNearbyPlaces(by: category?.name ?? "food", coordinates: currentLocation!, radius: radius, token: self.response?.nextPageToken, completion: didReceiveResponse)

       
    



    func didReceiveResponse(response:QNearbyPlacesResponse?, error : Error?) -> Void 
        if let error = error 
            let alertController = UIAlertController(title: "Error", message: error.localizedDescription, preferredStyle: .alert)
            let actionDismiss = UIAlertAction(title: "Dismiss", style: .cancel, handler: nil)
            let actionRetry = UIAlertAction(title: "Retry", style: .default, handler:  (action) in
                DispatchQueue.main.async 
                    self.loadPlaces(true)
                
            )
            alertController.addAction(actionRetry)
            alertController.addAction(actionDismiss)
            DispatchQueue.main.async 
                self.present(viewController: alertController)

            
        
        if let response = response 
            self.response = response
            if response.status == "OK" 
                if let placesDownloaded = response.places 
                    places.append(contentsOf: placesDownloaded)
                

               self.tableView?.reloadData()
             else 
                let alert = UIAlertController.init(title: "Error", message: response.status, preferredStyle: .alert)
                alert.addAction(UIAlertAction.init(title: "Cancel", style: .cancel, handler: nil))
                alert.addAction(UIAlertAction.init(title: "Retry", style: .default, handler:  (action) in
                    DispatchQueue.main.async 
                        self.loadPlaces(true)
                    
                ))
                 self.present(viewController: alert)
            
            isLoading = false
        
        else 
            print("response is nil")
        
    




    func numberOfSections(in tableView: UITableView) -> Int 

        print("numberOfsection Call")
        return 1
    





    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 

        print("numberOfRows Call")
        if places.count < self.numberPlaces 

        return  places.count   /*  rows   */
        
       return self.numberPlaces
    



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

        let cell = tableView.dequeueReusableCell(withIdentifier: resueIdentifier, for: indexPath) as! MyTableViewCell


        let place = places[indexPath.row]
        cell.update(place: place)

        if indexPath.row == places.count - 1 
            loadPlaces(false)
        
        print("CellForRow Call")
        return (cell)


    




     func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) 

        tableView.deselectRow(at: indexPath, animated: true)

        UIView.animate(withDuration: 0.2, animations: 
        let cell = tableView.dequeueReusableCell(withIdentifier: "MyTableViewCell", for: indexPath) as! MyTableViewCell
    )
         performSegue(withIdentifier: "goToLast" , sender: indexPath)

    




    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat 


     return 100





    func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool 
        return true
    




    func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) 

        if editingStyle == UITableViewCellEditingStyle.delete 

            places.remove(at: indexPath.row)
            tableView.deleteRows(at: [indexPath], with: .fade)

        

    

如果选择了多个类别的地点,我必须做什么才能在下一个 viewController 的 tableView 中显示每个选定类别的地点? (由于numberPlaces = HomeClass.globalLimit 可以显示的位置是有限的,最好的解决方案是每个选定类别至少有一个位置,其他位置随机添加)

编辑

indexPathsForSelectedRows 在哪里

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
        let identifier = "CATEGORY_CELL"
        let cell = tableView.dequeueReusableCell(withIdentifier: identifier, for: indexPath)
        let selectedIndexPaths = tableView.indexPathsForSelectedRows
        let rowIsSelected = selectedIndexPaths != nil && selectedIndexPaths!.contains(indexPath)
       /* cell.accessoryType = rowIsSelected ? .checkmark : .none  */
        cell.accessoryType = list[indexPath.row].isSelected ? .checkmark : .none
        cell.textLabel?.text = list[indexPath.row].name
        return cell
    

【问题讨论】:

在使用map 函数之前,indexPathsForSelectedRows 的值是否正确? @jvrmed 我编辑了问题 我的问题的意思是,当你点击你的segue时,如果你在prepare(for segue: UIStoryboardSegue, sender: Any?)的末尾放置一个断点,tableView.indexPathsForSelectedRows?的值是多少?可以在调试终端输入po tableView.indexPathsForSelectedRows?查看 还有,nearbySearchSegueIdentifier的值是多少 @jvrmed ok indexPathsForSelectedRows 的值是正确的,并且附近SearchSegueIdentifier 的值是字符串""goToMcourse"" 【参考方案1】:

显然你的问题是你的代码架构。在loadPlaces 上,您正在遍历您的类别并进行多次网络调用。然后将这些结果附加到places 并使用reloadData 重新加载表,但在cellForRowAt 上你再次调用loadPlaces

即使您在loadPlaces 中设置了isLoading = true,您也有多个请求正在进行,并且所有请求都在最后设置了isLoading = false。所以在某些时候你会得到一些意想不到的结果。您还有一些 force 负载情况,这些情况加起来。

最后但同样重要的是,由于您在闭包内调用 self.tableView?.reloadData(),因此它可能没有正确更新。

TL;DR

    reloadData 包裹在DispatchQueue.main.async 块周围。

    实施一个序列化您的网络请求的队列,以便为您的呼叫排序。例如,您可以使用 this 之类的库。

    let queue = TaskQueue()
    for category in categories 
     queue.tasks +=~  result, next in
         // Add your places request here
     
    
     queue.tasks +=! 
         // Reload your table here
     
    
     queue.run 
         // check your places array is correct
     
    
    

其他观察:

    您的title 将始终是categories 上的最后一个类别,因为您没有使用title = category?.name 上的所有数组。 为了更好地了解正在发生的事情,请尝试仅选择 2 个类别并查看是否存在加载某个类别的模式(始终为第一个,或始终为第二个)。如果根本没有模式,因为问题肯定是网络。

【讨论】:

我尝试只选择两个类别,结果完全随意 那么您需要重新考虑如何加载数据。触发多个修改同一个对象的网络请求是一种非常糟糕的做法。使用我建议的库添加您的 for category in categories 循环以将所有请求排入队列 看了你的库,不明白怎么做 您在哪里遍历您的类别 好的,最后一个问题,你能给我一个例子来说明如何添加地点请求并检查我的地点数组是否正确吗?抱歉所有这些问题,我是初学者,这是第一次处理此类论点

以上是关于我在表格视图中选择了一个地点类别列表,但在 segue 中它只发送一个的主要内容,如果未能解决你的问题,请参考以下文章

更新集合视图项

如何在表格视图中增加所选索引的字体颜色和字体大小?

如何根据选定的单元格在表格视图中设置启用的检查图像

如何创建从视图控制器到自身的 segue

IOS 7表格视图内容大小问题

如何根据集合视图中的单元格选择来控制表格视图的内容?