每天在特定时间调用函数一次 Swift

Call a function one time per day at a specific time Swift

我有一个表格视图,我想在每天的特定时间(用户输入选择器)清空它。这是它主要工作的代码,但假设用户在晚上 7 点打开应用程序,更新时间是晚上 8 点,数据没有被删除(这是正确的)但是当时间是当天晚上 9 点并且应用程序被打开时数据未被删除(这是不正确的)。我认为这与 lastRefreshDate 在每次打开应用程序时更新有关,并且必须从 lastRefreshDate 而不是 userPickedHour 等待 24 小时。该应用程序应该像这样工作,有一个固定时间晚上 7 点。所以当用户打开应用程序时,应用程序应该在第二天晚上 7 点或晚上 7 点之后删除数据,但是如果用户在第二天晚上 7 点之前打开应用程序,则不应删除数据,

代码如下:

class RefreshManager: NSObject {

static let shared = RefreshManager()
private let defaults = UserDefaults.standard
private let defaultsKey = "lastRefresh"
private let calender = Calendar.current



func loadDataIfNeeded(completion: (Bool) -> Void) {

    if isRefreshRequired() {
        // load the data
        defaults.set(Date(), forKey: defaultsKey)
        print("xxxxxx")
        completion(true)
    } else {
        print("yyyyyy")
        completion(false)
    }
}

private func isRefreshRequired(userPickedHour: Int = 16) -> Bool {
    let SleepPickerdate = UserDefaults.standard.object(forKey: "SleepDate") as? Date
    let userPickedHour = Calendar.current.component(.hour, from: (SleepPickerdate)!)
    print(userPickedHour)

    guard let lastRefreshDate = defaults.object(forKey: defaultsKey) as? Date else {
        return true
    }

    if let diff = calender.dateComponents([.hour], from: lastRefreshDate, to: Date()).hour,
        let currentHour =  calender.dateComponents([.hour], from: Date()).hour,
        diff >= 24, userPickedHour >= currentHour {

        print("Delete TableView")
        NotificationCenter.default.post(name: NSNotification.Name(rawValue: "Delete"), object: nil)
        print(diff)
        return true

    } else {

        print("Don't Delete TableView")

        return false


      }
    }
  }



class ViewController: UIViewController {

let refreshManager = RefreshManager.shared

override func viewDidLoad() {
    super.viewDidLoad()

    refreshManager.loadDataIfNeeded() { success in
        print(success)
    }
  }
}

您不能像 iOS 中那样使用长 运行 计时器。事实上,您无法让您的应用程序在一天中的特定时间调用函数。

短时间后,用户锁定 phone 并且您的应用会暂停以节省电池电量。

除非你是为越狱写的,否则没有办法做你要求做的事 phone。

编辑:

您说“我只想在特定时间后用户打开应用时看到 table查看数据已删除。”

Ok, that's different. When the app is open, calculate the date at which you want the records to be deleted.

将该日期保存到 UserDefaults。然后实现一个 applicationDidBecomeActive() 方法,在那个方法中,从 UserDefaults 中读取保存的日期,如果它已经通过,删除你在 table 视图中显示的数据。

您无法保证您的应用每天都在运行宁。 phone 可能会失去所有电池电量,应用程序可能不会 运行ning... 等等

但这只是一个逻辑问题...如果你想在每天的某个时间后刷新数据,你应该只在 UserDefaults 中存储最后一次刷新时间,如果那个时间超过你要求的到期时间时间(在本例中为 24 小时)然后刷新数据并更新上次更新时间。

因此,如果您有活跃用户,只要 24 小时时差到期,它就会刷新,或者如果用户 phone 关闭了几天(无论出于何种原因),您的应用程序仍会知道一旦用户返回应用程序就需要刷新数据。

编辑:添加了代码示例

class RefreshManager: NSObject {

    static let shared = RefreshManager()
    private let defaults = UserDefaults.standard
    private let defaultsKey = "lastRefresh"
    private let calender = Calendar.current

    func loadDataIfNeeded(completion: (Bool) -> Void) {

        if isRefreshRequired() {
            // load the data
            defaults.set(Date(), forKey: defaultsKey)
            completion(true)
        } else {
            completion(false)
        }
    }

    private func isRefreshRequired() -> Bool {

        guard let lastRefreshDate = defaults.object(forKey: defaultsKey) as? Date else {
            return true
        }

        if let diff = calender.dateComponents([.hour], from: lastRefreshDate, to: Date()).hour, diff > 24 {
            return true
        } else {
            return false
        }
    }
}

您真的不必像我一样将其设为新的 class 或单例。为了得到答案,将所有内容妥善保存起来会更容易。

因此,如果没有刷新日期,或者如果自上次更新以来的小时数大于 24,那么它将更新数据并更新上次刷新 date/time。使用完成它也会 return 无论它是否更新数据。

如果需要,您还可以在此处添加检查以确认当前时间是 >= 16

编辑 2:用户可选择的时间

private func isRefreshRequired(userPickedHour: Int = 16) -> Bool {

    guard let lastRefreshDate = defaults.object(forKey: defaultsKey) as? Date else {
        return true
    }

    if let diff = calender.dateComponents([.hour], from: lastRefreshDate, to: Date()).hour,
        let currentHour =  calender.dateComponents([.hour], from: Date()).hour,
        diff >= 24, userPickedHour <= currentHour {
        return true
    } else {
        return false
    }
}  

在这个修改后的 isRefreshRequired 函数中,您可以传递一个小时值,并查看自上次刷新以来是否已经至少 24 小时,以及当前小时是否等于或大于用户选择的小时。

这并不意味着它将 运行 顺便说一下,例如 16:00。它会 运行 当用户加载该屏幕并且规则通过时(至少 24 小时过去,currentHour >= userSelected 小时)

编辑 3:如何调用

class ViewController: UIViewController {

    let refreshManager = RefreshManager.shared

    override func viewDidLoad() {
        super.viewDidLoad()

        refreshManager.loadDataIfNeeded() { success in
            print(success)
        }
    }
}

编辑:更改逻辑

if let diff = calender.dateComponents([.day], from: lastRefreshDate, to: Date()).day,
    let currentHour =  calender.dateComponents([.hour], from: Date()).hour,
    diff >= 1, userPickedHour <= currentHour {
    return true
} else {
    return false
}

简单示例

例如,我们可以在“lastRefresh”中设置下一次更新的日期,这样,当该日期过去时,它会再次刷新它,设置下一次刷新的日期。

class RefreshManager: NSObject {

static let shared = RefreshManager()
private let defaults = UserDefaults.standard
private let defaultsKey = "lastRefresh"
private let calender = Calendar.current

func loadDataIfNeeded(completion: (Bool) -> Void) {
    if isRefreshRequired() {
        var date = Date()
        
        //Check for duration (Daily, Weekly or Monthly) (0,1,2)
        switch SaveManager.shared.user()!.UserShare.duration {
        case 0:
            //If user want to share daily
            date = date.addComponentsToDate(seconds: 0, minutes: 0, hours: 0, days: 1, weeks: 0, months: 0, years: 0)
            break
            
        case 1:
            //If user want to share weekly
            date = date.addComponentsToDate(seconds: 0, minutes: 0, hours: 0, days: 0, weeks: 1, months: 0, years: 0)
            break
            
        case 2:
            //If user want to share monthly
            date = date.addComponentsToDate(seconds: 0, minutes: 0, hours: 0, days: 0, weeks: 0, months: 1, years: 0)
            break
            
        default:
            //If user want to share daily : Default
            date = date.addComponentsToDate(seconds: 0, minutes: 0, hours: 0, days: 1, weeks: 0, months: 0, years: 0)
            break
        }

        date = date.startOfDay
        defaults.set(date, forKey: defaultsKey)
        print(date.toString())
        
        completion(true)
    } else {
        completion(false)
    }
}

private func isRefreshRequired() -> Bool {
    guard let lastRefreshDate = defaults.object(forKey: defaultsKey) as? Date else {
        return true
    }
    
    if lastRefreshDate.isLaterThanOrEqualTo(date: Date()) {
        return true
    } else {
        return false
    }
}}