如何保存倒数计时器的进度?

时间:2017-07-24 21:57:42

标签: ios swift timer delegates

所以我在swift中构建一个应用程序,为不同的任务设置一个长计时器。我希望能够保存计时器的进度,以便用户可以离开视图控制器并稍后再返回。

用户从tableView中选择一个任务,每个任务都附加了一段时间,并被绑定到一个实际的计时器。我希望用户能够在我的数据模型中留下计时器和剩余的更新时间。

到目前为止,我所做的工作似乎并不起作用,而且我不确定该怎么做。下面的代码供用户离开计时器并返回到表中。 TaskData是我的数据模型。

@IBAction func cancel(_ sender: Any) {
    let item = TaskData()
    item.time = String(seconds)
    dismiss(animated: true, completion: nil)
    delegate?.viewController(self, didFinishEditing: item)
}

在我的表视图控制器中,我使用下面的函数

func viewController(_ controller: ViewController, didFinishEditing item: TaskData) {
    if let index = tasks.index(of: item) {
        let indexPath = IndexPath(row: index, section: 0)
        if let cell = tableView.cellForRow(at: indexPath) {
            configureText(for: cell, with: item)
        }
    }
    dismiss(animated: true, completion: nil)
    saveTasklistItems()
}

当我从计时器(ViewController)转到表视图然后返回计时器时,计时器中剩余的时间将恢复为原来的时间。

以下是两个视图控制器的代码

import UIKit

class TaskListViewController: UITableViewController, 
AddNewTaskViewControllerDelegate, TimerViewControllerDelegate {

var tasks: [TaskData]

required init?(coder aDecoder: NSCoder) {

    tasks = [TaskData]()
    super.init(coder: aDecoder)
    loadChecklistItems()
}


//DELEGATE PROTOCOLS
func addNewTaskViewControllerDidCancel(_ controller: AddNewTaskViewController) {
    dismiss(animated: true, completion: nil)
}
func addNewTaskViewController(_ controller: AddNewTaskViewController, didFinishAdding item: TaskData) {
    let newRowIndex = tasks.count
    tasks.append(item)
    print(item.time)

    let indexPath = IndexPath(row: newRowIndex, section: 0)
    let indexPaths = [indexPath]
    tableView.insertRows(at: indexPaths, with: .automatic)

    dismiss(animated: true, completion: nil)
    saveTasklistItems()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "AddTask" {
        let navigationController = segue.destination as! UINavigationController
        let controller = navigationController.topViewController as! AddNewTaskViewController
        controller.delegate = self
    } else if segue.identifier == "ShowTimer" {
        let navigationController = segue.destination as! UINavigationController
        let controller = navigationController.topViewController as! ViewController
        if let indexPath = tableView.indexPath(for: sender as! UITableViewCell) {
            controller.timerTask = tasks[indexPath.row]
            controller.timerTime = tasks[indexPath.row]
        }
    }
}

func viewController(_ controller: ViewController, didFinishEditing item: TaskData) {
    if let index = tasks.index(of: item) {
        let indexPath = IndexPath(row: index, section: 0)
        if let cell = tableView.cellForRow(at: indexPath) {
            configureText(for: cell, with: item)
        }
    }
    dismiss(animated: true, completion: nil)
    saveTasklistItems()
}
///////////////////////////////

func configureText(for cell: UITableViewCell, with item: TaskData) {
    let label = cell.viewWithTag(2) as! UILabel
    label.text = item.time
}

override func viewDidLoad() {
    super.viewDidLoad()

    // Do any additional setup after loading the view.
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {

    tasks.remove(at: indexPath.row)
    let indexPaths = [indexPath]
    tableView.deleteRows(at: indexPaths, with: .automatic)
    saveTasklistItems()
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return tasks.count
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "TaskListItem", for: indexPath)

    let taskItem = tasks[indexPath.row]
    let label = cell.viewWithTag(1) as! UILabel
    let label2 = cell.viewWithTag(2) as! UILabel
    label.text = taskItem.task
    label2.text = taskItem.time
    return cell
}

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

}

//SAVE FUNCTIONALITY
func documentsDirectory() -> URL {
    let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
    return paths[0]
}
func dataFilePath() -> URL {
    return documentsDirectory().appendingPathComponent("Tasklists.plist")
}
func saveTasklistItems() {
    let data = NSMutableData()
    let archiver = NSKeyedArchiver(forWritingWith: data)
    archiver.encode(tasks, forKey: "TasklistItems")
    archiver.finishEncoding()
    data.write(to: dataFilePath(), atomically: true)
}

func loadChecklistItems() {
    let path = dataFilePath()
    if let data = try? Data(contentsOf: path) {
        let unarchiver = NSKeyedUnarchiver(forReadingWith: data)
        tasks = unarchiver.decodeObject(forKey: "TasklistItems") as! [TaskData]
        unarchiver.finishDecoding()
    }
}
}

上面是tableView,下面我会发布计时器

import UIKit

protocol TimerViewControllerDelegate: class {
func viewController(_ controller: ViewController, didFinishEditing item: TaskData)
}

class ViewController: UIViewController, UITextFieldDelegate {

@IBOutlet weak var timerLabel: UILabel!
@IBOutlet weak var pauseButton: UIButton!
@IBOutlet weak var startButton: UIButton!
@IBOutlet weak var timerTaskName: UILabel!
@IBOutlet weak var timerTimeSetting: UILabel!
@IBOutlet weak var progressView: UIProgressView!

weak var delegate: TimerViewControllerDelegate?

var timerTask: TaskData?
var timerTime: TaskData?
var seconds: Int = 0
var timer = Timer()
var isTimerRunning = false
var resumeTapped = false
var progressViewSpeed: Double = 0.0

//THIS BUTTON CREATS AN UPDATED TASK DATA TIME MEMBER
@IBAction func cancel(_ sender: Any) {
    let item = TaskData()
    item.time = String(seconds)
    print(item.time)
    dismiss(animated: true, completion: nil)
    delegate?.viewController(self, didFinishEditing: item)
}
/////////////////////////////


@IBAction func startButtonTapped(_ sender: Any) {

    if isTimerRunning == false {
        runTimer()
        self.startButton.isEnabled = false
    }
    if seconds >= (500 * 60 * 60) {
        seconds = (500 * 60 * 60)
    }
}

func runTimer() {
    timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: (#selector(ViewController.updateTimer)), userInfo: nil, repeats: true)
    isTimerRunning = true
    pauseButton.isEnabled = true
}

@IBAction func pauseButtonTapped(_ sender: UIButton) {
    if self.resumeTapped == false {
        timer.invalidate()
        self.resumeTapped = true
        self.pauseButton.setTitle("Resume",for: .normal)
    } else {
        runTimer()
        self.resumeTapped = false
        self.pauseButton.setTitle("Pause",for: .normal)
    }
}

/*
@IBAction func resetButtonTapped(_ sender: Any) {
    timer.invalidate()
    seconds = 60
    self.timerLabel.text = timeString(time: TimeInterval(seconds))
    if self.resumeTapped == true {
        self.resumeTapped = false
        self.pauseButton.setTitle("Pause",for: .normal)
    }
    isTimerRunning = false
    pauseButton.isEnabled = false
    startButton.isEnabled = true
}
*/

func updateTimer() {
    if seconds < 1 {
        timer.invalidate()
        //Send alert to indicate "time's up!"
    } else {
        seconds -= 1
        timerLabel.text = timeString(time: TimeInterval(seconds))
    }
    progressViewSpeed = 1 / Double(seconds)
    progressView.progress += Float(progressViewSpeed)
}

func timeString(time:TimeInterval) -> String {
    let hours = Int(time) / 3600
    let minutes = Int(time) / 60 % 60
    let seconds = Int(time) % 60
    return String(format:"%02i:%02i:%02i", hours, minutes, seconds)
}

override func viewDidLoad() {
    super.viewDidLoad()
    pauseButton.isEnabled = false

    if let task = timerTask {
        timerTaskName.text = task.task
    }

    if let timerTimeLeft = timerTime {
        timerTimeSetting.text = timerTimeLeft.time
    }

    //I SOLVED A SERIOUS ERROR HERE
    let timeLeft: Int? = Int(timerTimeSetting.text!)
    seconds = Int(timeLeft!) * 60 * 60
    self.timerLabel.text = timeString(time: TimeInterval(seconds))
    ///////////////////////////////

    self.progressView.transform = CGAffineTransform.identity.rotated(by: CGFloat.pi / 2).scaledBy(x: 1, y: 150)


}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}
}

2 个答案:

答案 0 :(得分:1)

启动计时器时,将当前日期作为时间间隔保存到实例变量中:

定义实例变量:

var startTime: TimeInterval = 0.0
var elapseTime: TimeInterval = 0.0
let totalTime = 100.0 //Replace with your desired total time

weak var timer: Timer?

然后你可以使用这样的代码:

@IBAction func startButtonTapped(_ sender: Any) {
  //save the current date as a time interval
  startTime = Date().timeIntervalSinceReferenceDate
  timer = Timer.scheduledTimer(timeInterval: 1, 
    target: self, 
    selector: #selector(ViewController.updateTimer), 
    userInfo: nil, 
    repeats: true)
}

@IBAction func pauseTimer(_ sender: Any) {
   timer.invalidate()
   //Calculate the amount of time that's passed since starting the timer
   elapsedTime = Date().timeIntervalSinceReferenceDate - startTime

   //Calculate the amount of time remaining
   timeRemaining = totalTime - elapsedTime
   //Save timeRemaining to UserDefaults or do whatever you desire with it.
}

这是一个非常粗略的轮廓。您需要弄清楚细节,但这应该让您开始。

答案 1 :(得分:0)

保存TaskData数组及其相应的开始时间和/或结束时间,并将该数组保存到UserDefaults