离线情况下准确的时间检测

12

背景信息

我正在开发一个连接到服务器的iOS应用程序,设备可以向服务器发出请求,以便将本地数据库与服务器数据库进行同步。两个数据库中的任何一个都可能发生更改。该应用程序还具有脱机功能,其中用户可以在未连接互联网的情况下修改数据,并且只有在在线状态下,通过向服务器发送新数据并从服务器接收更新,才能将设备的本地数据库与服务器的数据库进行同步。

添加更多背景信息:处理的数据是必须在一定时间内完成的表格。开始时间存储为模型的属性,并使用该属性,应用程序向用户显示在此表格被锁定之前剩余的时间。


问题

当设备处于脱机状态时,用户可以操纵时间设置,这将使从该设备接收的数据不准确。

我已经搜索了一种检测设备时间设置更改的方法,但根据这个SO答案,除非我的应用程序在后台运行,否则似乎无法实现,而苹果公司对此非常严格,并且不允许除非应用程序启用了其中一个后台模式,但这些后台模式在该应用程序中不适用。

添加更多信息:正如我在背景信息的更新部分中提到的那样,处理的数据是可以有时间限制的表格。因此,用户可以在一个设备上开始一张表格,但不能在那里完成它。然后他们将数据同步到服务器,跳转到另一个设备并完成相同的表格。


建议解决方案

我已经接近解决这个问题,即在安装应用程序时获得服务器时间和设备时间之间的差异(第一次打开应用程序时一定在线以配置该设备),并在存储与时间相关的值时使用此差异作为参考。

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

问题在于,当设备离线时,用户可以更改时间设置,对数据进行更改,然后在联网前将时间设置返回到之前的状态。然后,服务器将检测不到时间设置的更改,并接受无效数据。

更新以添加另一个提出的解决方案:为了更详细地阐述下面的问题和与 @Krypton 的评论,设备的正常运行时间对我的情况没有太大帮助,因为与上述解决方案存在相同的问题。

将设备的正常运行时间与服务器时间进行比较是完美的,直到用户重新启动设备。它不能由用户手动更改,但只需要一次重新启动就可以破坏所有内容,这会为我产生相同的不准确数据。要修复它,需要计算新差异,这在设备离线时无法帮助。


问题

  1. 是否有一个不可更改的时间戳可以用作参考,以保存与时间相关的值,以便用户更改设备时间时不会受到影响?例如,设备首次激活以来的时间。(注意:我找到的与此相关的最接近的内容是设备的正常运行时间,但在我的情况下并不太有用)
  2. 是否有一种方法可以知道当前时间,而无需每次保存与时间相关的值时都需要联网?
  3. 是否有修复我提出的解决方案或任何更好的解决方案的方法?

2
一个提示:自设备启动以来经过的时间单调且不断增加。 - Krypton
我考虑使用设备启动后经过的时间来计算与服务器当前时间的差异。这个时间可能无法被用户更改,但是如果用户重新启动设备,它将会改变,那么我将面临同样的问题,对吧? - hannad
2
如果设备重新启动,应用程序需要连接到服务器以再次获取正确的启动时间。 - Krypton
有时候这是不可能的,这就是为什么我在寻找一些即使在重新启动后也能持久存在的东西。 - hannad
2
很抱歉,这已经是我们所能做的最好的了。据我所知,你只能使用两种东西来跟踪时间:系统时钟和CPU时钟(用于测量类似正常运行时间的时间)。如果您不信任系统时钟,则只能依赖CPU时钟(不能在重启后保存)。 - Krypton
显示剩余4条评论
3个回答

3

获取设备时间有三种方法。

  1. NSDate。用户可以修改的时间。
  2. mach_absolute_time。这是设备的绝对时间。但正如你所指出的,这会在设备重启时破坏一切。此外,当设备暂停时,这将变得不正确。
  3. 引导时间。自从启动以来的时间。使用uptime来获取。

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

现在仍然存在重新启动设备的问题。如果您能够获取设备启动的时间,就可以计算出上次保存的NSDate和引导时间之间的差异。幸运的是,这是可能的。请参见this answer或其他答案,以了解可能的实现方式。请注意,实施此操作可能会导致小的(1-10秒)不准确性。

另一个选择是在设备重新启动后没有互联网连接的情况下不允许应用程序启动。
此外,NSSystemClockDidChangeNotification 应该能够提供帮助。
编辑:这是我会做的。请记住,这并不完美,无论您选择什么,都会有权衡。
当您有互联网连接时,可以定期获取服务器时间并将其保存在模型中。这样可以计算设备时间和服务器时间之间的时间差。您可以通过在模型中保存uptimeNSDate的时间戳来实现此操作。如果设备没有重置,则使用uptime。计算启动的NSDate请参见此处),然后重新开始测量。如果这些差异发生了显着变化,那么您就知道时间已被篡改。请记住,即使用户未更改时间(测量错误、夏令时等),这些差异也会发生显着变化。对于您的应用程序而言,您认为显着变化的定义因情况而异。
然后,您必须决定如果时间已更改,您想要做什么。您可以考虑计算所需时间是否超过最大时间(如果设备没有重置,则使用uptime),或者可能完全放弃更改。

请您能否再详细解释一下这些组合如何一起使用?如果设备的时间设置发生变化,我该如何处理? - hannad
1
在这种情况下,您可以自行决定如何处理。您可以考虑尝试计算实际时间或完全拒绝更改。如何做取决于您的模型和确切目标。我将编辑问题以解释我将如何处理此事。 - Belle
我会认真考虑这个问题。在我得出结果之前可能需要一些时间再回复您。感谢您的建议。 - hannad
2
你怎么知道设备是否重新启动了?你需要获取设备的启动时间,对吧?然而,设备的启动时间的更改可能是由于篡改尝试或真正的重新启动。你的解决方案仍然没有回答如何在重新启动后继续运行。 - Krypton
2
在我的第5个评论中解释了,我认为唯一的解决方案是如果发现引导时间与当前时间 - 正常运行时间不匹配,则从服务器重新获取时间。 - Krypton
有其他问题涉及如何找到设备已重新启动。你是对的,你只知道时间被篡改了。那么你需要服务器。 - Belle

0

你永远不能依赖于两个设备拥有相同的时间。我建议服务器应该使用递增的时间戳,如果你从服务器获取了带有服务器时间戳X的数据,那么你所记录的本地更改只是知道你的更改是“在服务器时间戳X之后的某个时间”,而不是准确的时间。无论你的设备认为更改是何时进行的。如果服务器给你的信息带有今天的时间戳11:20:47.003692,并且你进行了更改,而你设备上的时间是10:15:15:000000,那么这个更改并不是在10:15进行的,而是“在服务器的11:20:47.003692之后进行的”。


我更新了我的问题,添加了一些我认为可能缺失的背景信息。如上所述,这些数据实际上是必须在特定时间内完成的表单,用户在一个设备上开始填写表单,然后在另一个设备上完成它并不罕见。如果我只需要知道更改相对于以前更改的时间,以上解决方案的确有效,但是在我的情况下,恐怕需要更精确。 - hannad

0

我也遇到了同样的问题,你的解决方案很有帮助,谢谢。你忽略的一点是,当系统时钟改变或重新启动设备时,你可以通过它改变了多少(多少秒)来判断。你需要做的就是根据系统时钟改变的秒数调整你存储的时间。

类似于这样... if(iBootTime != iBootTimeBefore) dtMyTime.addTimeInterval(timeInterval:TimeInterval(iBootTime - iBootTimeBefore))


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接