创建对象时设置计时器倒计时

时间:2015-10-29 14:39:20

标签: swift nsdate swift2 countdown

我在Parse的几个对象中查询createdAt日期。我想创建一个24小时(或48/72等)countDown计时器,它从创建对象到24小时后倒计时。 (然后我也将其格式化,并将其显示在单元格UILabel上。)

示例:如果一个对象是在19:34:33创建的,我希望它在此之后24小时到期(或者在创建它之后指定多少小时)。最终在UILabel上显示物品到期前的剩余时间。

目前,我在创建时检索,使其从创建时开始重复倒计时。

但是,我想制作逻辑,以便在创建对象时生成逻辑,然后显示在24小时或48小时,72小时等之前剩余的小时数。

编辑

感谢@pulsar,我在下面的描述中添加了几行代码。现在的问题是我只能检索并正确计算1对象的createdAt日期和时间,因为 查询第一个对象,使所有其他对象具有相同的expiration countDown计时器在它们各自的indexPath.row中作为Parse中的第一个对象。

我无法弄清楚如何添加所有对象,以便它们都有自己的expiresAt函数触发的countDown到期时间。

以下是我如何查询并格式化它(在 viewDidLoad 中): 这是我问的问题,帮我格式化日期:Swift countDown timer Logic

请参阅代码中的评论!

            var createdAt = object.createdAt
            if createdAt != nil {


                 //assuming this is where i have to set expiration logic?

                let calendar = NSCalendar.currentCalendar()
                let comps = calendar.components([.Hour, .Minute, .Second], fromDate: createdAt as NSDate!)
                let hours = comps.hour  * 3600
                let minutes = comps.minute * 60
                let seconds = comps.second

                 //I'm adding these two lines below but not sure what to do with them considering I need to add all the objects to an array that will then display it on indexPath.row(s)

                   let twentyFourHours = NSTimeInterval(60 * 60 * 24)
                    self.expiresAt = NSDate(timeInterval: twentyFourHours, sinceDate: object.createdAt!!)


                self.timerInt.append(hours + minutes + seconds)
                //What do i append to the timerInt array? How can i append the objects while triggering the the expiresAt function? 

           } 

这是我的countDown函数:

               func countDown() {

        //timerInt is an array where I'm storing the Int values.
        for i in 0 ..< timerInt.count {

            let hours = timerInt[i] / 3600 
          //have to somehow add the expiresAt method while looping through each value [i]...?
            let minsec = timerInt[i] % 3600
            let minutes = minsec / 60
            let seconds = minsec % 60
       print(String(format: "%02d:%02d:%02d", hours, minutes, seconds))
          timerInt[i]--

           //Im assuming best practice would be to loop through the values in order to change the values/set the expiration time to each object (the expiresAt method). Any ideas of how and where I can add this in this loop so that it reflects the countDown I want to set?

        }

        self.tableView.reloadData()

}

最后,对于我的indexPath.row,我正在格式化它并显示如下:

          override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
         let myCell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! cell

  //I'm formatting the hours, minutes, seconds. However I'm missing the expiresAt function and I have no clue as to where and how to include it... Should it be here or in the countDown() loop?  

     let hours = timerInt[indexPath.row] / 3600
     let minsec = timerInt[indexPath.row] % 3600
     let minutes = minsec / 60
     let seconds = minsec % 60


      myCell.secondLabel.text = String(format: "%02d:%02d:%02d", hours, minutes, seconds)


        return myCell
}

关于如何在创建后24/48/72小时将其设置为倒计时的想法?

非常感谢任何和所有帮助!

2 个答案:

答案 0 :(得分:1)

Sounds like what you need is to set the expiry date and then get the date components between the current date and the expiry date. Then you can use an NSTimer to refresh the display. (Don't forget to call NSTimer.invalidate() when you're done).

An example:

class YourViewController: UIViewController {

    var expiresAt: NSDate?

    func viewDidLoad() {
        // your parse logic here
        let twentyFourHours = NSTimeInterval(60 * 60 * 24)
        expiresAt = NSDate(timeInterval: twentyFourHours, sinceDate: createdAt)
        scheduleTimer()
    }

    func scheduleTimer() {
        NSTimer.scheduledTimerWithTimeInterval(1.0 / 30.0, target: self, selector: "tick:", userInfo: nil, repeats: true)
    }

    @objc
    func tick(timer: NSTimer) {
        guard let expiresAt = expiresAt else {
            return
        }
        let calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)
        if let components = calendar?.components([.Hour, .Minute, .Second], fromDate: NSDate(), toDate: expiresAt, options: []) {
            print(formatDateComponents(components))
        }
    }

    func formatDateComponents(components: NSDateComponents) -> String {
        let hours = components.hour
        let minutes = components.minute 
        let seconds = components.second
        return "\(hours):\(minutes):\(seconds)"
    }

}

You could also make your life much easier by using a structure to store the date components rather than doing that complicated parsing of your timerInt strings.

struct Time {
    let hours: String
    let minutes: String
    let seconds: String
}

答案 1 :(得分:1)

//: Playground - noun: a place where people can play

import XCPlayground
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
import UIKit

class MyView: UIView {
    weak var l1: UILabel?
    weak var l2: UILabel?
    weak var l3: UILabel?

    let validFor: NSTimeInterval
    var validTo: NSDate = NSDate()

    lazy var timer: NSTimer = NSTimer(timeInterval: self.validFor, target: self, selector: "done", userInfo: nil, repeats: false)

    init(validFor: NSTimeInterval) {
        self.validFor = validFor
        super.init(frame: CGRect(x: 0, y: 0, width: 500, height: 100))
        validTo = timer.fireDate

        let ll1 = UILabel(frame: CGRect(x: 1, y: 1, width: 498, height: 30))
        ll1.text = "created at: \(NSDate())"
        self.addSubview(ll1)
        l1 = ll1

        let ll2 = UILabel(frame: CGRect(x: 1, y: 33, width: 498, height: 30))
        ll2.text = "valid to: \(validTo)"
        self.addSubview(ll2)
        l2 = ll2

        let ll3 = UILabel(frame: CGRect(x: 1, y: 66, width: 498, height: 30))
        ll3.text = "valid for next: \(validTo.timeIntervalSinceNow) second"
        self.addSubview(ll3)
        l3 = ll3

        NSRunLoop.currentRunLoop().addTimer(timer, forMode: NSRunLoopCommonModes)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    // when MyView expires it trigers this function
    // and give me a chance to update UI
    func done() {
        // update UI
        dispatch_async(dispatch_get_main_queue(), { [unowned self] () -> Void in
            self.l2?.text = "     EXPIRED"
            self.l3?.text = ""
            if let text1 = self.l1?.text,
                let text2 = self.l2?.text,
                let text3 = self.l3?.text
            {
                print("")
                print(text1, text2, text3)

            }
        })
    }
    func updateState() {
        // periodically updating UI on request
        if timer.valid {
            let v = validTo.timeIntervalSinceNow

            // update UI
            dispatch_async(dispatch_get_main_queue(), { [unowned self] () -> Void in
                self.l3?.text = "valid for next: \(v) second"
                if let text1 = self.l1?.text,
                    let text2 = self.l2?.text,
                    let text3 = self.l3?.text
                {

                    print(text1, text2, text3)


                }
            })
        }
    }
}


let c = MyView(validFor: 10.0) // in seconds

let queue = dispatch_queue_create("update", DISPATCH_QUEUE_SERIAL)

// periodic action tu update UI
// in regular intervals
// this is just for demonstration, avoid using use sleep
// in real application
dispatch_async(queue) { () -> Void in
    repeat {
        c.updateState()
        sleep(3)
    } while true
}

dispatch_async(dispatch_get_main_queue(), { () -> Void in
    print("the app is running and responding on user actions")
    print("MyView labels are updating 'automatically'\n")
})

print("playground continue ....\n")