我在表格视图中选择了一个地点类别列表,但在 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 中它只发送一个的主要内容,如果未能解决你的问题,请参考以下文章