Ios TableView单元格保持更改顺序

Ios TableView单元格保持更改顺序,ios,swift,xcode,uitableview,Ios,Swift,Xcode,Uitableview,我正在制作的计时器应用程序出现了一些奇怪的情况: 我每0.25秒更新一次每个单元格的内容,但有时会出现这种奇怪的小故障/错误(表视图单元格的顺序不断变化): 更新计时器的代码: override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { var noRows = 0 let appDelegate = UIApplication.share

我正在制作的计时器应用程序出现了一些奇怪的情况:

我每0.25秒更新一次每个单元格的内容,但有时会出现这种奇怪的小故障/错误(表视图单元格的顺序不断变化):

更新计时器的代码:

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

    var noRows = 0

    let appDelegate = UIApplication.shared.delegate as! AppDelegate
    let context = appDelegate.persistentContainer.viewContext
    let request = NSFetchRequest<NSFetchRequestResult>(entityName: "TimersData")
    request.returnsObjectsAsFaults = false

    do {
        let results = try context.fetch(request)

        if segmentedControl.selectedSegmentIndex == 0 {
            noRows = results.count
        }
        else {
            for result in results as! [NSManagedObject] {
                if let activityIndicator = result.value(forKey: "activity") as? String {
                    if activityIndicator == "active" {
                        noRows += 1
                    }
                }
            }
        }

    }
    catch {

    }

    return noRows
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    var activity = ""

    let appDelegate = UIApplication.shared.delegate as! AppDelegate
    let context = appDelegate.persistentContainer.viewContext
    let request = NSFetchRequest<NSFetchRequestResult>(entityName: "TimersData")
    request.returnsObjectsAsFaults = false

    do {
        let results = try context.fetch(request)

        if results.count > 0 {
            if segmentedControl.selectedSegmentIndex == 0 {

                let result = (results as! [NSManagedObject])[indexPath.row]
                if let activityIndicator = result.value(forKey: "activity") as? String {
                    activity = activityIndicator
                }

                var timerString = ""
                var hourString = ""
                var minuteString = ""
                var secondString = ""
                if let seconds = result.value(forKey: "timerSeconds") as? Int {
                    if let secondsLeftDouble = result.value(forKey: "timerProgress") as? Double {
                        let secondsLeft: Int = Int(round(secondsLeftDouble))
                        if seconds < 1 {
                        }
                        else if seconds >= 5 && seconds < 60 { // ss
                            timerString = "\(secondsLeft)s"
                        }
                        else if seconds >= 60 && seconds < 3600 { // mm:ss
                            let minute = secondsLeft / 60
                            minuteString = "\(minute)"
                            if minute < 10 {

                                minuteString = "0\(minute)"

                            }
                            let second = secondsLeft % 60
                            var secondString: String = "\(second)"
                            if second < 10 {

                                secondString = "0\(second)"

                            }
                            timerString = "\(minuteString):\(secondString)"

                        }
                        else if seconds >= 3600 && seconds <= 86400 { // hh:mm:ss
                            let hourString: String = "\(secondsLeft / 3600)"
                            let minute = (secondsLeft % 3600) / 60
                            var minuteString: String = "\(minute)"
                            if minute < 10 {

                                minuteString = "0\(minute)"

                            }
                            let second = (secondsLeft % 3600) % 60
                            var secondString: String = "\(second)"
                            if second < 10 {

                                secondString = "0\(second)"

                            }
                            timerString = "\(hourString):\(minuteString):\(secondString)"
                        }
                    }
                }

                var timerTitle = ""
                if let title = result.value(forKey: "timerName") as? String {
                    timerTitle = title
                }

                let cell = tableView.dequeueReusableCell(withIdentifier: "active", for: indexPath) as! activeTableViewCell
                cell.configureCell(name: timerTitle, time: timerString, activityIndicator: activity, indexPathToSend: indexPath.row)
                return cell

                /* if activity == "active" {
                    let cell = tableView.dequeueReusableCell(withIdentifier: "active", for: indexPath) as! activeTableViewCell
                    cell.configureCell(name: timerTitle, time: timerString)
                    return cell
                }
                else if activity == "paused" {
                    let cell = tableView.dequeueReusableCell(withIdentifier: "paused", for: indexPath) as! pausedTableViewCell
                    cell.configureCell(name: timerTitle, time: timerString)
                    return cell
                }
                else if activity == "none" {
                    let cell = tableView.dequeueReusableCell(withIdentifier: "inactive", for: indexPath) as! nonactiveTableViewCell
                    cell.configureCell(name: timerTitle, time: timerString)
                    return cell
                }
                else {
                    let cell = tableView.dequeueReusableCell(withIdentifier: "inactive", for: indexPath) as! nonactiveTableViewCell
                    cell.configureCell(name: timerTitle, time: timerString)
                    return cell
                } */

            }
            else {
                var i = 0
                activeTimersArray = []
                for result in results as! [NSManagedObject] {
                    if let activityIndicator = result.value(forKey: "activity") as? String {
                        if activityIndicator == "active" {
                            activeTimersArray.append(i)
                        }
                    }
                    i += 1
                }

                if indexPath.row < activeTimersArray.count {
                    let result = (results as! [NSManagedObject])[activeTimersArray[indexPath.row]]

                    var timerString = ""
                    var hourString = ""
                    var minuteString = ""
                    var secondString = ""
                    if let seconds = result.value(forKey: "timerSeconds") as? Int {
                        if let secondsLeftDouble = result.value(forKey: "timerProgress") as? Double {
                            let secondsLeft: Int = Int(round(secondsLeftDouble))
                            if seconds < 1 {
                            }
                            else if seconds >= 5 && seconds < 60 { // ss
                                timerString = "\(secondsLeft)s"
                            }
                            else if seconds >= 60 && seconds < 3600 { // mm:ss
                                let minute = secondsLeft / 60
                                minuteString = "\(minute)"
                                if minute < 10 {

                                    minuteString = "0\(minute)"

                                }
                                let second = secondsLeft % 60
                                var secondString: String = "\(second)"
                                if second < 10 {

                                    secondString = "0\(second)"

                                }
                                timerString = "\(minuteString):\(secondString)"

                            }
                            else if seconds >= 3600 && seconds <= 86400 { // hh:mm:ss
                                let hourString: String = "\(secondsLeft / 3600)"
                                let minute = (secondsLeft % 3600) / 60
                                var minuteString: String = "\(minute)"
                                if minute < 10 {

                                    minuteString = "0\(minute)"

                                }
                                let second = (secondsLeft % 3600) % 60
                                var secondString: String = "\(second)"
                                if second < 10 {

                                    secondString = "0\(second)"

                                }
                                timerString = "\(hourString):\(minuteString):\(secondString)"
                            }
                        }
                    }

                    var timerTitle = ""
                    if let title = result.value(forKey: "timerName") as? String {
                        timerTitle = title
                    }

                    let cell = tableView.dequeueReusableCell(withIdentifier: "active", for: indexPath) as! activeTableViewCell
                    cell.configureCell(name: timerTitle, time: timerString, activityIndicator: "active", indexPathToSend: indexPath.row)
                    return cell
                }
                else {
                    let cell = tableView.dequeueReusableCell(withIdentifier: "active", for: indexPath) as! activeTableViewCell
                    cell.configureCell(name: "Processing", time: "Processing", activityIndicator: "active", indexPathToSend: indexPath.row)
                    return cell
                }


            }

        }
        else {
            /* let cell = tableView.dequeueReusableCell(withIdentifier: "inactive", for: indexPath) as! nonactiveTableViewCell
            cell.configureCell(name: "Error", time: "Error")
            return cell */

            let cell = tableView.dequeueReusableCell(withIdentifier: "active", for: indexPath) as! activeTableViewCell
            cell.configureCell(name: "Error", time: "Error", activityIndicator: "none", indexPathToSend: indexPath.row)
            return cell
        }
    }
    catch {
        /* let cell = tableView.dequeueReusableCell(withIdentifier: "inactive", for: indexPath) as! nonactiveTableViewCell
        cell.configureCell(name: "Error", time: "Error")
        return cell */

        let cell = tableView.dequeueReusableCell(withIdentifier: "active", for: indexPath) as! activeTableViewCell
        cell.configureCell(name: "Error", time: "Error", activityIndicator: "none", indexPathToSend: indexPath.row)
        return cell
    }

}
计时器:

timer = Timer.scheduledTimer(timeInterval: 0.25, target: self, selector: #selector(processTimer), userInfo: nil, repeats: true)
processTimer()函数:

@objc func processTimer() {
    let appDelegate = UIApplication.shared.delegate as! AppDelegate
    let context = appDelegate.persistentContainer.viewContext
    let request = NSFetchRequest<NSFetchRequestResult>(entityName: "TimersData")
    request.returnsObjectsAsFaults = false

    do {
        let results = try context.fetch(request)

        var i = 0
        if results.count > 0 {
            for result in results as! [NSManagedObject] {
                if let activityIndicator = result.value(forKey: "activity") as? String {
                    if activityIndicator == "active" {
                        if let startDate = result.value(forKey: "startDate") as? Date {
                            var seconds = startDate.timeIntervalSinceNow
                            seconds = seconds * -1
                            if let timerSeconds = result.value(forKey: "timerSeconds") as? Int {
                                if let timerProgress = result.value(forKey: "timerProgress") as? Double {
                                    var newSeconds: Double = timerProgress - seconds
                                    if newSeconds < 0 {
                                        newSeconds = 0
                                    }
                                    result.setValue(newSeconds, forKey: "timerProgress")
                                    let now = Date()
                                    result.setValue(now, forKey: "startDate")
                                    do {
                                        try context.save()
                                    }
                                    catch {
                                        print("error")
                                    }
                                    result.setValue(Date(), forKey: "startDate")
                                    // TEST OUT datesArray[i] = Date()
                                }
                            }
                            else {
                                result.setValue(Date(), forKey: "startDate")
                                // TEST OUT datesArray[i] = Date()
                            }
                        }
                        else {
                            result.setValue(Date(), forKey: "startDate")
                        }
                    }
                    else {
                        result.setValue(nil, forKey: "startDate")
                        // TEST OUT datesArray[i] = nil
                    }
                }
                i += 1
            }
        }

    }
    catch {

    }

    // tableView.reloadData()
    let indexPathsArray = tableView.indexPathsForVisibleRows
    for indexPath in indexPathsArray! {

        var activity = ""

        let appDelegate = UIApplication.shared.delegate as! AppDelegate
        let context = appDelegate.persistentContainer.viewContext
        let request = NSFetchRequest<NSFetchRequestResult>(entityName: "TimersData")
        request.returnsObjectsAsFaults = false

        do {
            let results = try context.fetch(request)

            if results.count > 0 {
                if segmentedControl.selectedSegmentIndex == 0 {

                    let result = (results as! [NSManagedObject])[indexPath.row]
                    if let activityIndicator = result.value(forKey: "activity") as? String {
                        activity = activityIndicator
                    }

                    var timerString = ""
                    var hourString = ""
                    var minuteString = ""
                    var secondString = ""
                    if let seconds = result.value(forKey: "timerSeconds") as? Int {
                        if let secondsLeftDouble = result.value(forKey: "timerProgress") as? Double {
                            let secondsLeft: Int = Int(floor(1*secondsLeftDouble)/1)
                            if seconds < 1 {
                            }
                            else if seconds >= 5 && seconds < 60 { // ss
                                timerString = "\(secondsLeft)s"
                            }
                            else if seconds >= 60 && seconds < 3600 { // mm:ss
                                let minute = secondsLeft / 60
                                minuteString = "\(minute)"
                                if minute < 10 {

                                    minuteString = "0\(minute)"

                                }
                                let second = secondsLeft % 60
                                var secondString: String = "\(second)"
                                if second < 10 {

                                    secondString = "0\(second)"

                                }
                                timerString = "\(minuteString):\(secondString)"

                            }
                            else if seconds >= 3600 && seconds <= 86400 { // hh:mm:ss
                                let hourString: String = "\(secondsLeft / 3600)"
                                let minute = (secondsLeft % 3600) / 60
                                var minuteString: String = "\(minute)"
                                if minute < 10 {

                                    minuteString = "0\(minute)"

                                }
                                let second = (secondsLeft % 3600) % 60
                                var secondString: String = "\(second)"
                                if second < 10 {

                                    secondString = "0\(second)"

                                }
                                timerString = "\(hourString):\(minuteString):\(secondString)"
                            }
                        }
                    }

                    var timerTitle = ""
                    if let title = result.value(forKey: "timerName") as? String {
                        timerTitle = title
                    }

                    let cell = tableView.cellForRow(at: indexPath) as! activeTableViewCell
                    cell.configureCell(name: timerTitle, time: timerString, activityIndicator: activity, indexPathToSend: indexPath.row)

                    /* if activity == "active" {
                        let cell = tableView.cellForRow(at: indexPath) as! activeTableViewCell
                        cell.configureCell(name: timerTitle, time: timerString)
                        cell.sendIndexPath(indexPathToSend: indexPath.row)
                    }
                    else if activity == "paused" {
                        let cell = tableView.cellForRow(at: indexPath) as! pausedTableViewCell
                        cell.configureCell(name: timerTitle, time: timerString)
                    }
                    else if activity == "none" {
                        let cell = tableView.cellForRow(at: indexPath) as! nonactiveTableViewCell
                        cell.configureCell(name: timerTitle, time: timerString)
                    }
                    else {
                        let cell = tableView.cellForRow(at: indexPath) as! nonactiveTableViewCell
                        cell.configureCell(name: timerTitle, time: timerString)
                    } */

                }
                else {
                    var i = 0
                    activeTimersArray = []
                    for result in results as! [NSManagedObject] {
                        if let activityIndicator = result.value(forKey: "activity") as? String {
                            if activityIndicator == "active" {
                                activeTimersArray.append(i)
                            }
                        }
                        i += 1
                    }

                    if indexPath.row < activeTimersArray.count {
                        let result = (results as! [NSManagedObject])[activeTimersArray[indexPath.row]]

                        var timerString = ""
                        var hourString = ""
                        var minuteString = ""
                        var secondString = ""
                        if let seconds = result.value(forKey: "timerSeconds") as? Int {
                            if let secondsLeftDouble = result.value(forKey: "timerProgress") as? Double {
                                let secondsLeft: Int = Int(round(secondsLeftDouble))
                                if seconds < 1 {
                                }
                                else if seconds >= 5 && seconds < 60 { // ss
                                    timerString = "\(secondsLeft)s"
                                }
                                else if seconds >= 60 && seconds < 3600 { // mm:ss
                                    let minute = secondsLeft / 60
                                    minuteString = "\(minute)"
                                    if minute < 10 {

                                        minuteString = "0\(minute)"

                                    }
                                    let second = secondsLeft % 60
                                    var secondString: String = "\(second)"
                                    if second < 10 {

                                        secondString = "0\(second)"

                                    }
                                    timerString = "\(minuteString):\(secondString)"

                                }
                                else if seconds >= 3600 && seconds <= 86400 { // hh:mm:ss
                                    let hourString: String = "\(secondsLeft / 3600)"
                                    let minute = (secondsLeft % 3600) / 60
                                    var minuteString: String = "\(minute)"
                                    if minute < 10 {

                                        minuteString = "0\(minute)"

                                    }
                                    let second = (secondsLeft % 3600) % 60
                                    var secondString: String = "\(second)"
                                    if second < 10 {

                                        secondString = "0\(second)"

                                    }
                                    timerString = "\(hourString):\(minuteString):\(secondString)"
                                }
                            }
                        }

                        var timerTitle = ""
                        if let title = result.value(forKey: "timerName") as? String {
                            timerTitle = title
                        }

                        let cell = tableView.cellForRow(at: indexPath) as! activeTableViewCell
                        cell.configureCell(name: timerTitle, time: timerString, activityIndicator: "active", indexPathToSend: indexPath.row)
                    }
                    else {
                        let cell = tableView.cellForRow(at: indexPath) as! activeTableViewCell
                        cell.configureCell(name: "Processing", time: "Processing", activityIndicator: "active", indexPathToSend: indexPath.row)
                    }


                }

            }
            else {
                // let cell = tableView.cellForRow(at: indexPath) as! nonactiveTableViewCell
                // cell.configureCell(name: "Error", time: "Error")
                let cell = tableView.cellForRow(at: indexPath) as! activeTableViewCell
                cell.configureCell(name: "Error", time: "Error", activityIndicator: "none", indexPathToSend: indexPath.row)
            }
        }
        catch {
            // let cell = tableView.cellForRow(at: indexPath) as! nonactiveTableViewCell
            // cell.configureCell(name: "Error", time: "Error")

            let cell = tableView.cellForRow(at: indexPath) as! activeTableViewCell
            cell.configureCell(name: "Error", time: "Error", activityIndicator: "none", indexPathToSend: indexPath.row)
        }
    }
}
@objc func processTimer(){
让appDelegate=UIApplication.shared.delegate为!appDelegate
让上下文=appDelegate.persistentContainer.viewContext
let request=NSFetchRequest(entityName:“TimersData”)
request.returnsObjectsAsFaults=false
做{
let results=try context.fetch(请求)
变量i=0
如果results.count>0{
对于结果,结果为![NSManagedObject]{
如果让activityIndicator=result.value(forKey:“活动”)作为?字符串{
如果activityIndicator==“活动”{
如果让startDate=result.value(forKey:“startDate”)作为?日期{
var seconds=startDate.timeintervalncesnow
秒=秒*-1
如果让timerSeconds=result.value(forKey:“timerSeconds”)为?Int{
如果让timerProgress=result.value(forKey:“timerProgress”)为?Double{
var newSeconds:Double=timerProgress-seconds
如果newSeconds<0{
newSeconds=0
}
result.setValue(newSeconds,forKey:“timerProgress”)
让我们现在=日期()
result.setValue(现在,forKey:“startDate”)
做{
尝试context.save()
}
抓住{
打印(“错误”)
}
result.setValue(Date(),forKey:“startDate”)
//测试日期ray[i]=日期()
}
}
否则{
result.setValue(Date(),forKey:“startDate”)
//测试日期ray[i]=日期()
}
}
否则{
result.setValue(Date(),forKey:“startDate”)
}
}
否则{
结果.设定值(零,forKey:“起始日期”)
//测试日期Ray[i]=无
}
}
i+=1
}
}
}
抓住{
}
//tableView.reloadData()
让indexPathsArray=tableView.IndExpathForVisibleRows
对于indexPathsArray中的indexPath{
var activity=“”
让appDelegate=UIApplication.shared.delegate为!appDelegate
让上下文=appDelegate.persistentContainer.viewContext
let request=NSFetchRequest(entityName:“TimersData”)
request.returnsObjectsAsFaults=false
做{
let results=try context.fetch(请求)
如果results.count>0{
如果segmentedControl.selectedSegmentIndex==0{
让结果=(结果为![NSManagedObject])[indexPath.row]
如果让activityIndicator=result.value(forKey:“活动”)作为?字符串{
活动=活动指示器
}
var timerString=“”
var hourString=“”
var minuteString=“”
var secondString=“”
如果let seconds=result.value(forKey:“timerSeconds”)为?Int{
如果让secondsLeftDouble=result.value(forKey:“timerProgress”)为?Double{
让secondsLeft:Int=Int(楼层(1*secondsLeftDouble)/1)
如果秒数小于1{
}
否则,如果秒数>=5&&seconds<60{//ss
timerString=“\(secondsLeft)s”
}
否则,如果秒数>=60&&seconds<3600{//mm:ss
让分钟=秒英尺/60
minuteString=“\(分钟)”
如果分钟<10{
minuteString=“0\(分钟)”
}
设秒=秒英尺%60
var secondString:String=“\(秒)”
如果秒小于10{
secondString=“0\(秒)”
}
timerString=“\(minuteString):\(第二个字符串)”
}
否则,如果秒数>=3600&&seconds=5&&seconds<60{//ss
timerString=“\(secondsLeft)s”
}
否则,如果秒数>=60&&seconds<3600{//mm:ss
让分钟=秒英尺/60
minuteString=“\(分钟)”
如果分钟<10{
minuteString=“0\(分钟)”
}
设秒=秒英尺%60
var secondString:String=“\(秒)”
如果秒小于10{
secondString=“0\(秒)”
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "TimersData")
request.sortDescriptors = [NSSortDescriptor(key:"startDate", ascending: true)]