Ios UITableView:reloadRows(at:)需要两次点击才能更新表并每次滚动
我有一个表视图(controller:MetricsViewController),它从CoreData数据库更新。我使用了原型单元(MetricsViewCell),我根据自己的需要定制了原型单元。它包含一个分段控件、一个UIView(metricsChart,用于显示图表动画圆)和一些UILabel MetricsViewCell:Ios UITableView:reloadRows(at:)需要两次点击才能更新表并每次滚动,ios,swift,uitableview,core-data,reloaddata,Ios,Swift,Uitableview,Core Data,Reloaddata,我有一个表视图(controller:MetricsViewController),它从CoreData数据库更新。我使用了原型单元(MetricsViewCell),我根据自己的需要定制了原型单元。它包含一个分段控件、一个UIView(metricsChart,用于显示图表动画圆)和一些UILabel MetricsViewCell: class MetricsViewCell: UITableViewCell { var delegate: SelectSegmentedC
class MetricsViewCell: UITableViewCell {
var delegate: SelectSegmentedControl?
var animatedCircle: AnimatedCircle?
@IBOutlet weak var percentageCorrect: UILabel!
@IBOutlet weak var totalPlay: UILabel!
@IBOutlet weak var metricsChart: UIView! {
didSet {
animatedCircle = AnimatedCircle(frame: metricsChart.bounds)
}
}
@IBOutlet weak var recommendationLabel: UILabel!
@IBOutlet weak var objectType: UISegmentedControl!
@IBAction func displayObjectType(_ sender: UISegmentedControl) {
delegate?.tapped(cell: self)
}
}
protocol SelectSegmentedControl {
func tapped(cell: MetricsViewCell)
}
class MetricsViewController: FetchedResultsTableViewController, SelectSegmentedControl {
func tapped(cell: MetricsViewCell) {
if let indexPath = tableView.indexPath(for: cell) {
tableView.reloadRows(at: [indexPath], with: .none)
}
}
var container: NSPersistentContainer? = (UIApplication.shared.delegate as? AppDelegate)?.persistentContainer { didSet { updateUI() } }
private var fetchedResultsController: NSFetchedResultsController<Object>?
private func updateUI() {
if let context = container?.viewContext {
let request: NSFetchRequest<Object> = Object.fetchRequest()
request.sortDescriptors = []
fetchedResultsController = NSFetchedResultsController<Object>(
fetchRequest: request,
managedObjectContext: context,
sectionNameKeyPath: "game.gameIndex",
cacheName: nil)
try? fetchedResultsController?.performFetch()
tableView.reloadData()
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Object Cell", for: indexPath)
if let object = fetchedResultsController?.object(at: indexPath) {
if let objectCell = cell as? MetricsViewCell {
objectCell.delegate = self
let request: NSFetchRequest<Object> = Object.fetchRequest()
...
...
}
}
}
return cell
}
MetricsViewController:
class MetricsViewCell: UITableViewCell {
var delegate: SelectSegmentedControl?
var animatedCircle: AnimatedCircle?
@IBOutlet weak var percentageCorrect: UILabel!
@IBOutlet weak var totalPlay: UILabel!
@IBOutlet weak var metricsChart: UIView! {
didSet {
animatedCircle = AnimatedCircle(frame: metricsChart.bounds)
}
}
@IBOutlet weak var recommendationLabel: UILabel!
@IBOutlet weak var objectType: UISegmentedControl!
@IBAction func displayObjectType(_ sender: UISegmentedControl) {
delegate?.tapped(cell: self)
}
}
protocol SelectSegmentedControl {
func tapped(cell: MetricsViewCell)
}
class MetricsViewController: FetchedResultsTableViewController, SelectSegmentedControl {
func tapped(cell: MetricsViewCell) {
if let indexPath = tableView.indexPath(for: cell) {
tableView.reloadRows(at: [indexPath], with: .none)
}
}
var container: NSPersistentContainer? = (UIApplication.shared.delegate as? AppDelegate)?.persistentContainer { didSet { updateUI() } }
private var fetchedResultsController: NSFetchedResultsController<Object>?
private func updateUI() {
if let context = container?.viewContext {
let request: NSFetchRequest<Object> = Object.fetchRequest()
request.sortDescriptors = []
fetchedResultsController = NSFetchedResultsController<Object>(
fetchRequest: request,
managedObjectContext: context,
sectionNameKeyPath: "game.gameIndex",
cacheName: nil)
try? fetchedResultsController?.performFetch()
tableView.reloadData()
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Object Cell", for: indexPath)
if let object = fetchedResultsController?.object(at: indexPath) {
if let objectCell = cell as? MetricsViewCell {
objectCell.delegate = self
let request: NSFetchRequest<Object> = Object.fetchRequest()
...
...
}
}
}
return cell
}
class MetricsViewController:FetchedResultsTableViewController,SelectedSegmentedControl{
函数(单元格:MetricsViewCell){
如果让indexPath=tableView.indexPath(for:cell){
tableView.reloadRows(位于:[indexPath],带:。无)
}
}
var容器:NSPersistentContainer?=(UIApplication.shared.delegate作为?AppDelegate)?.persistentContainer{didSet{updateUI()}
私有变量fetchedResultsController:NSFetchedResultsController?
私有func updateUI(){
如果let context=container?.viewContext{
let请求:NSFetchRequest=Object.fetchRequest()
request.sortDescriptors=[]
fetchedResultsController=NSFetchedResultsController(
fetchRequest:request,
managedObjectContext:context,
sectionNameKeyPath:“game.gameIndex”,
缓存名称:nil)
尝试?获取结果控制器?.performFetch()
tableView.reloadData()
}
}
重写func tableView(tableView:UITableView,cellForRowAt indexath:indexPath)->UITableViewCell{
let cell=tableView.dequeueReusableCell(带有标识符:“对象单元格”,用于:indexath)
如果let object=fetchedResultsController?.object(位于:indexPath){
如果让objectCell=单元格为?MetricsViewCell{
objectCell.delegate=self
let请求:NSFetchRequest=Object.fetchRequest()
...
...
}
}
}
返回单元
}
当用户选择某个节的分段控件中的一个分段时,MetricsViewController应重新加载该特定行中的数据。(有两个部分,每个部分一行)。因此,我在MetricsViewCell中定义了一个协议来通知我的控制器用户操作
正在使用FetchedResultsTableViewController更新数据,该控制器基本上充当CoreData和TableView之间的委托。这一切都很好,这意味着我正在将正确的数据输入到我的TableView中
有两个问题:
Edit:为我使用CoreData和持久容器添加了更多的上下文。在接收要调用的单元格对象时,可以直接使用
indexPath(for:)
,而不是使用indexPathForRow(at:)
函数获取单元格的indexPath对象(cell:MetricsViewCell){}并尝试更新UI上的数据,始终在主线程中,如下所示
func tapped(cell: MetricsViewCell) {
if let lIndexPath = table.indexPath(for: <#T##UITableViewCell#>){
DispatchQueue.main.async(execute: {
table.reloadRows(at: lIndexPath, with: .none)
})
}
}
func(单元格:MetricsViewCell){
如果让lIndexPath=table.indepath(for:){
DispatchQueue.main.async(执行:{
table.reloadRows(at:lindh,带:.none)
})
}
}
您的UISegmentedControl
正在重用[UITableView的默认行为]
要避免这种情况,请使用字典
获取和存储值
另一件事,在UIViewController
本身中,尝试UITableViewCell的UISegmentedControl
插座连接作为操作,而不是UITableViewCell
点击UISegmentedControl
时,下面的代码将不会重新加载tableview。你可以避免,代表们也会打电话
以下代码是UISegmentedControl
的基本演示。根据您的需要进行定制
var segmentDict = [Int : Int]()
override func viewDidLoad() {
super.viewDidLoad()
for i in 0...29 // number of rows count
{
segmentDict[i] = 0 //DEFAULT SELECTED SEGMENTS
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! SOTableViewCell
cell.mySegment.selectedSegmentIndex = segmentDict[indexPath.row]!
cell.selectionStyle = .none
return cell
}
@IBAction func mySegmentAcn(_ sender: UISegmentedControl) {
let cellPosition = sender.convert(CGPoint.zero, to: tblVw)
let indPath = tblVw.indexPathForRow(at: cellPosition)
segmentDict[(indPath?.row)!] = sender.selectedSegmentIndex
print("Sender.tag ", indPath)
}
2.要避免滚动,请尝试在没有动画的情况下重新加载行。目前您正在指定自动动画。如何确定点击哪个段控件?。每个单元格都有自己的分段控件,但无法使用。遗憾的是,没有动画。这是默认的动画。您是否在代码中的任何位置滚动?在您的函数中,点击(单元格:)
然后您创建indepath
的方式似乎是错误的。这里有几个错误。您正在将行硬编码为零。我正在使用我的应用程序代理容器的viewContext更新数据。viewContext在主线程上运行,因此这不是问题。不过我还是尝试了显式主线程,但不起作用:(@mnanium)获取单元格的indexpath对象怎么样?尝试过吗?是的,这与@user1046037:func tapped(cell:MetricsViewCell){if let indexpath=tableView.indexpath(for:cell){DispatchQueue.main.async的建议相同{self.tableView.reloadRows(在:[indexath],with:.none)}}}你也可以放弃投票吗?这对如此多的追随者有用吗?