【问题标题】:Getting system uptime in iOS/Swift在 iOS/Swift 中获取系统正常运行时间
【发布时间】:2016-07-12 05:58:04
【问题描述】:

有没有办法在 iOS 中获得系统正常运行时间(使用 Swift)?我需要的是测量时间,而不必担心用户更改时间。在 Android 中,有一个 elapsedCurrentTimeMillis() 返回自启动以来的毫秒数,但现在我需要类似的东西用于 iOS。 Getting iOS system uptime, that doesn't pause when asleep 这里有一个公认的答案,但那是针对 Objective C 的,我需要它用于 Swift,但我不知道如何转换它。

【问题讨论】:

  • NSProcessInfo.processInfo().systemUptime 怎么样?
  • 这没有考虑睡眠时间。我需要一种方法来可靠地测量已经过去了多少时间,即使应用程序在此期间关闭并且即使用户更改了时间。

标签: ios swift


【解决方案1】:

当您要求纯 Swift 解决方案时,我从您提到的答案 Getting iOS system uptime, that doesn't pause when asleep 转换了 ObjC 代码。

func uptime() -> time_t {
    var boottime = timeval()
    var mib: [Int32] = [CTL_KERN, KERN_BOOTTIME]
    var size = strideof(timeval)

    var now = time_t()
    var uptime: time_t = -1

    time(&now)
    if (sysctl(&mib, 2, &boottime, &size, nil, 0) != -1 && boottime.tv_sec != 0) {
        uptime = now - boottime.tv_sec
    }
    return uptime
}

// print(uptime())

为了让它更漂亮一点,我们可以使用sysctlbyname 而不是sysctl

// var mib: [Int32] = [CTL_KERN, KERN_BOOTTIME]
sysctlbyname("kern.boottime", &boottime, &size, nil, 0)

【讨论】:

  • @JAL 我调试并找出了 ObjC 和 Swift 之间 sizeof 的不同行为。现在可以了!
  • 是的,这行得通,显示与 Objective-C 代码版本相同的值!而且我可以看到我将很难编程......
  • 我在 swift 5 中收到 Use of unresolved identifier 'strideof' 错误。看起来语法已更改,但我不确定要做什么
  • @Anushk 将 strideof(timeval) 替换为 MemoryLayout<timeval>.stride
【解决方案2】:

这是 Swift 4 中的解决方案。

 var boottime = timeval()
 var size = MemoryLayout<timeval>.stride
 sysctlbyname("kern.boottime", &boottime, &size, nil, 0) 

【讨论】:

    【解决方案3】:

    为 Swift 5 更新,直接来自 ADF 帖子here

    func bootTime() -> Date? {  
        var tv = timeval()  
        var tvSize = MemoryLayout<timeval>.size  
        let err = sysctlbyname("kern.boottime", &tv, &tvSize, nil, 0);  
        guard err == 0, tvSize == MemoryLayout<timeval>.size else {  
            return nil  
        }  
        return Date(timeIntervalSince1970: Double(tv.tv_sec) + Double(tv.tv_usec) / 1_000_000.0)  
    }
    

    “请注意,如果系统时钟发生变化,这个时间会发生变化,即该值是相对于当前系统时钟的启动时间。”

    【讨论】:

    • 取决于系统时钟变化的启动时间点是多少?他们改变了这种行为还是什么?
    【解决方案4】:

    您可以从 Swift 中调用 ObjC 代码:

    print(SystemUtil().uptime());
    

    编写一个 ObjC 类,就像您提到的公认答案:Getting iOS system uptime, that doesn't pause when asleep

    SystemUtil.h 用于接口:

    #import <Foundation/Foundation.h>
    
    @interface SystemUtil : NSObject
    
    - (time_t)uptime;
    
    @end
    

    SystemUtil.m 实现:

    #import "SystemUtil.h"
    #include <sys/sysctl.h>
    
    @implementation SystemUtil
    
    - (time_t)uptime
    {
        struct timeval boottime;
        int mib[2] = {CTL_KERN, KERN_BOOTTIME};
        size_t size = sizeof(boottime);
        time_t now;
        time_t uptime = -1;
    
        (void)time(&now);
    
        if (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1 && boottime.tv_sec != 0) {
            uptime = now - boottime.tv_sec;
        }
        return uptime;
    }
    
    @end
    

    并且不要忘记在&lt;Project&gt;-Bridge-Header.h 中包含以下内容,以便您可以使用 Swift 中的 ObjC 类(&lt;Project&gt; 是您的项目名称):

    #import "SystemUtil.h"
    

    【讨论】:

    • OP 要求提供原生 Swift 解决方案。
    • 这行得通。我想。它显示了合理的非零正常运行时间。对于像我这样愚蠢的人,您需要做的就是在 Xcode 中创建 .h 和 .m 文件(文件->新建->文件...->iOS->源)并将@donghua-li的内容放入其中写了,Bridge-Header.h 将被自动创建(所以只需添加#import)
    • @TimSim 我制定了一个pure-Swift solution
    猜你喜欢
    • 2013-01-25
    • 2012-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-27
    • 1970-01-01
    相关资源
    最近更新 更多