离线时精确的时间检测

背景信息

我正在开发连接到服务器的iOS应用程序,并且可以从设备向服务器发出请求,以使本地数据库与服务器的数据库同步。 任何一个数据库都可能发生更改。 该应用程序还具有脱机function,用户可以在不连接到互联网连接的情况下修改数据,只通过发送新数据和从服务器接收更新来使设备的本地数据库与服务器的数据库同步。

更新了更多背景信息:处理的数据是必须在一定时间内完成的表单。 开始的时间作为属性存储在模型中,并且使用该属性,应用程序向用户显示该表单被locking之前还剩多less时间。


问题

当设备处于离线状态时,用户可以操纵时间设置,这会使从该设备收到的数据不准确。

我已经search了一种方法来检测设备时间设置的变化,但根据这个答案 ,这似乎不可能,除非我的应用程序在后台运行,苹果是非常严格的,并且不允许,除非应用程序启用了其中一种背景模式 ,这在应用程序中是不适用的。

更新了更多的信息:正如我在上面提到的背景信息的更新部分所述,数据是可能有时间限制的表格。 因此用户可以在一个设备上启动一个表单,但是不能在那里完成。 然后,他们将数据同步到服务器,跳转到另一个设备,并完成相同的forms。


build议的解决scheme

我最近解决这个问题的方法是,在安装应用程序时获取服务器时间和设备时间之间的差异(在第一次打开应用程序时确保在线,以便为此设备进行configuration),并且每当我想存储一个时间相关的值时,使用这个差别作为参考。

如果服务器检测到时间差异,它将拒绝来自该设备的所有数据,这将迫使设备恢复数据,更新时间差,只有这样才能从该设备接受数据。

问题是,当设备处于脱机状态时,用户可以更改时间设置,对数据执行更改,然后将时间设置返回到上一次联机之前的时间设置。 然后,服务器将检测到时间设置没有变化,并将接受无效的数据。

更新以添加另一个build议的解决scheme:在下面的问题中详细解释我的注释,以及@Krypton的注释,由于与上述解决scheme相同的问题,设备的正常运行时间对我的情况没有多大帮助。

将设备的正常运行时间与服务器时间进行比较是完美的, 直到用户重新启动设备 。 这不是用户可以手动更改的,但是所有这一切都需要重新启动才能打破一切,这将为我产生相同的不准确数据。 解决这个问题需要计算新的差异,这在设备离线时不起作用。


问题

  1. 是否存在不可更改的时间戳,可以在保存与时间相关的值时用作参考,使其不受用户对设备时间的更改影响? 这个例子就是设备第一次激活的时间。 ( :最接近我发现任何相关的是设备的正常运行时间 ,但这并没有什么帮助我的情况)
  2. 有没有办法知道当前的时间,而不需要上网,只要一个时间相关的值将被保存?
  3. 有没有办法来解决我提出的解决scheme,或更好的解决scheme?

有三种方法可以让设备上的时间。

  1. NSDate 。 用户可以修改的时间。
  2. mach_absolute_time 。 这是设备的绝对时间。 但正如你所指出的那样,这将在设备重新启动的时候破坏一切。 而且,当设备暂停时,这将不正确。
  3. 开机时间。 自启动以来的时间。 使用uptime来获得这个。

您将需要使用NSDateuptime的组合。 也许你可以保存对表单进行的任何更改的时间戳。 您将能够计算这些变化值之间的差异,并为您的应用程序进行必要的计算。 如果可能的话,您可能还想保存并与服务器时间进行比较。

现在仍然存在重启设备的问题。 如果您能够读取设备启动的时间,则可以计算上次保存的NSDate与启动时间之间的差异。 幸运的是,这是可能的。 看到这个答案或任何其他答案可能的方式来这样做。 请注意,执行这可能会导致一个小的(1-10秒)不准确。

另一种select是不允许应用程序在设备重启后没有networking连接的情况下启动。

此外, NSSystemClockDidChangeNotification应该能够提供帮助。

编辑:这我将如何做到这一点。 请记住,这不是完美的,无论你select什么,都会有折衷。

当你有互联网连接时,你可以每隔一段时间取一次服务器时间,并将其保存在模型中。 这使您可以计算设备时间和服务器时间之间的时间差。 您可以通过将uptimeNSDate作为时间戳保存在模型中来实现。 如果设备尚未重置,请使用uptime 。 计算启动的NSDate ( 请参阅此处 ),然后再次开始测量。 如果这些差异显着变化,你就知道时间被篡改了。 请记住,即使用户不改变时间(测量错误,夏令时…),这些差异也会改变。 你认为很重要的是你的应用程序。

那么如果时间已经改变,你必须决定你想做什么。 您可以考虑计算所用的时间是否不超过最大值(如果设备尚未重置,则使用uptime ),或者可以放弃所有更改。

你永远不能依靠两台同时使用的设备。 我build议服务器应该使用不断增加的时间戳,如果你从服务器获得服务器的时间戳X的数据,那么你应该logging本地的变化是知道你的变化是“服务器时间戳后的一段时间X“,没有任何准确的时间。 独立于您的设备何时认为发生了变化。 如果服务器为您提供了今天11:20:47.003692时间戳的信息,并且您进行了更改并且设备上的时间为10:15:15:000000,则在10:15时不会进行更改,但是“服务器上11:20:47.003692之后”。

我有同样的问题,你的解决scheme谢谢。 你错过的是当系统时钟改变或你重新启动你的设备时,你可以告诉它有多less改变(多less秒)。 所有你需要做的就是调整你的存储时间,系统时钟改变的秒数。

就像… if(iBootTime != iBootTimeBefore) dtMyTime.addTimeInterval(timeInterval:TimeInterval(iBootTime - iBootTimeBefore))