Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/100.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios UITableView:reloadRows(at:)需要两次点击才能更新表并每次滚动_Ios_Swift_Uitableview_Core Data_Reloaddata - Fatal编程技术网

Ios UITableView:reloadRows(at:)需要两次点击才能更新表并每次滚动

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

我有一个表视图(controller:MetricsViewController),它从CoreData数据库更新。我使用了原型单元(MetricsViewCell),我根据自己的需要定制了原型单元。它包含一个分段控件、一个UIView(metricsChart,用于显示图表动画圆)和一些UILabel

MetricsViewCell

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中

有两个问题:

  • 我必须点击分段控件的段两次,才能在点击分段控件的行中重新加载数据

  • 每次从segmented control中选择一个段时,表格都会上下滚动

  • 非常感谢您的帮助。我在开发过程中遇到的许多问题都依赖于这个社区,我已经很感激了:)

    例如,在动物识别部分,我必须点击“中间”两次才能重新加载它的行(如果你仔细观察,我第一次点击中间,它会被选中一小部分秒,然后它会返回到“基本”或第一次选择的任何片段。第二次点击中间,它会被选中)。另外,表格上下滚动,这是我不想要的


    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)}}}你也可以放弃投票吗?这对如此多的追随者有用吗?