Ios TableView单元格保持更改顺序
我正在制作的计时器应用程序出现了一些奇怪的情况: 我每0.25秒更新一次每个单元格的内容,但有时会出现这种奇怪的小故障/错误(表视图单元格的顺序不断变化): 更新计时器的代码: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
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)]