我正在开发一个连接到服务器的iOS应用程序,并且可以从设备向服务器发出请求,以使本地数据库与服务器的数据库同步。任何一个数据库都可能发生更改。该应用程序还具有离线功能,用户可以在不连接到互联网连接的情况下修改数据,并且只有在线才能将设备的本地数据库与服务器的数据库同步,通过发送新功能数据并从服务器接收更新。
更新了更多背景信息:处理的数据是必须在一定时间内完成的表单。它的启动时间作为属性存储在模型上,并且使用所述属性,应用程序向用户显示锁定此表单之前剩余的时间。
当设备离线时,用户可以操作时间设置,这会使从此设备接收的数据不准确。
我已经搜索了一种检测设备时间设置更改的方法但是根据this SO answer,除非我的应用程序在后台运行,否则这似乎是不可能的,Apple非常严格,并且不允许,除非应用程序启用了background modes之一,这在应用程序中不适用。
更新了更多信息:正如我在上面背景信息的更新部分中提到的,数据是可能有时间限制的表单。因此,用户可以在一个设备上启动表单,但不能在那里完成。然后,他们会将数据同步到服务器,跳转到另一台设备并完成相同的表单。
我最接近解决此问题的方法是在安装应用程序时获取服务器时间和设备时间之间的差异(确保在第一次打开应用程序时联机以便为此设备配置它,并在我想存储与时间相关的值时使用此差异作为参考。
如果服务器检测到时间差异,它将拒绝来自此设备的所有数据,这将强制设备恢复数据,更新时间差,然后才能从此设备接收数据。 / p>
问题在于,当设备处于脱机状态时,用户可以更改时间设置,对数据执行更改,然后将时间设置恢复为之前的状态,然后再联机。然后,服务器将检测到时间设置中没有变化,并接受无效数据。
更新以添加另一个建议的解决方案:要详细说明下面的问题中的说明以及@Krypton的评论,设备的正常运行时间对我的情况没有多大帮助,因为与上述解决方案相同的问题。
将设备的正常运行时间与服务器时间进行比较是完美的,直到用户重新启动设备。它不是由用户手动更改的,但是只需要一次重启就可以破坏所有内容,这会为我产生相同的不准确数据。修复它需要计算新的差异,这在设备离线时无济于事。
答案 0 :(得分:3)
有三种方法可以在设备上获得时间。
NSDate
。用户可以修改的时间。 mach_absolute_time
。这是设备的绝对时间。但正如您所指出的,这会破坏设备重启的一切。此外,当设备暂停时,这将不正确。uptime
来获取此信息。您需要使用NSDate
和uptime
的组合。也许您可以保存对表单所做的任何更改的时间戳。您将能够计算这些值在更改时的任何差异,并为您的应用程序执行必要的计算。如果可能,您可能还希望保存并与服务器时间进行比较。
现在仍然存在重启设备的问题。如果您能够获取设备启动的时间,则可以计算上次保存的NSDate
与启动时间之间的差异。幸运的是,这是可能的。有关可能的方法,请参阅this answer或任何其他答案。请注意,实施此操作可能会导致小的(1-10秒)不准确。
另一个选项是在设备重启后,不允许应用在没有互联网连接的情况下启动。
此外,NSSystemClockDidChangeNotification
应该可以提供帮助。
编辑:我将如何做到这一点。请记住,这并不完美,无论您选择什么,都会有权衡。
当您有互联网连接时,您可以经常获取服务器时间并将其保存在模型中。这允许您计算设备时间和服务器时间之间的时间差。您可以将uptime
和NSDate
保存为模型中的时间戳,从而实现此目的。如果设备尚未重置,请使用uptime
。计算引导NSDate
(see here),然后重新开始测量。如果这些差异发生显着变化,您就会知道时间被篡改了。请记住,即使用户没有更改时间(测量错误,夏令时......), 的这些差异也会发生变化。您的考虑很大程度上取决于您的应用程序。
然后,如果时间已经改变,你必须决定你想做什么。您可以考虑计算所用时间是否不超过最大值(如果设备尚未重置,则使用uptime
)或者可以完全放弃更改。
答案 1 :(得分:0)
你永远不可能依赖两个具有相同时间的设备。我建议服务器应该使用增加的时间戳,如果你从服务器获得带有服务器时间戳X的数据,那么所有你应该记录本地更改的是你知道你的更改是“在服务器时间戳之后的某个时间X“,没有任何准确的时间。并且独立于您的设备何时认为进行了更改。如果服务器为您提供了今天时间戳为11:20:47.003692的信息,并且您进行了更改并且设备上的时间为10:15:15:000000,那么该更改不会在10:15进行,但是“在服务器上11:20:47.003692之后”。
答案 2 :(得分:0)
我遇到了同样的问题,你的解决方案也有所帮助。您错过的是,当系统时钟发生变化或您重启设备时,您可以知道它已被更改了多少(多少秒)。您需要做的就是调整系统时钟更改的秒数。
像......
if(iBootTime != iBootTimeBefore)
dtMyTime.addTimeInterval(timeInterval:TimeInterval(iBootTime - iBootTimeBefore))