我正在制作的计时器应用程序发生了一些奇怪的事情:
每0.25秒,我会更新每个单元格的内容,但有时会出现这种奇怪的故障/错误(表视图单元格不断更改顺序):
更新计时器的代码:
计时器:
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)
}
}
}
TableView数据源的代码:
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
}
}
忽略任何评论-他们只是我在尝试解决其他问题。
答案 0 :(得分:0)
出于性能原因,核心数据可以无顺序保存记录。
如果您想要特定的订单,则需要应用适当的排序描述符
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "TimersData")
request.sortDescriptors = [NSSortDescriptor(key:"startDate", ascending: true)]
用所需的属性名称替换startDate
。
对于在每次cellForRow
调用中每秒四次获取Core Data对象的可疑必要性,没有评论。