iOS內部時鐘 – iPhone手機開發 iPhone軟體開發教學課程

1.什麼是內部時鐘

 

     在我們做iOS開發的過程中,我們經常要與時間打交道,[NSDate date]是我們常用的取時間的一種方式,但是[NSDate date] 這種方式隻能取系統的當前時間。也就是說:當前我們手機的時間是什麼時間,取出來的值,就是多少。

 

    如果用戶把系統的時間改瞭呢?那麼[NSDate date]取出來的值,還是我們想要的嗎???在一些應用的開發中,我們在沒有網絡的狀態下,不能取網絡時間,依靠系統時間,是可以篡改的。所以這個時候,我們要自己要在程序的內部定制一個自己的內部時鐘。

 

 

 

2.實現內部時鐘的思路

 

    1.要有一個時間作為基本的參照點(一般應用都會與服務器打交道,所以發請求給服務器,取服務器的時間是比較合適的)

 

    2.要有一個標記點(一般取待機時長)

 

    3.在每次進入程序的時候,或者登錄的時候,取服務器的時間存起來,然後再取當前的待機時間存起來,每次要獲取當前時間的時候,再取待機時長跟之前的存儲的待機時長比較,獲得差值。將存儲的服務器時間加上差值,就獲得想要的當前時間。

 

 

 

3.具體實現步驟

 

   0.用到的宏:

 

 

//開機時間
#define SWStartTime  @"startTime"

//服務器時間
#define SWServerTime @"serverTime"

//登錄時的待機時長
#define SWSinceNow @"sinceNow"

 

 

 

   1.獲取待機時長

 

 

<br>/**
 *  待機時間(從系統啟動的那一刻開始獲取的時間間隔)
 */
+ (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;
     
}

 

 

 2.存儲服務器時間及待機時長

 

 

/**
 *  存儲服務器時間及待機時長
 *
 *  @param serverTime 服務器時間
 */
+ (void)firstTimeWithLogin:(NSString *)serverTime
{
        NSTimeInterval timer = (NSTimeInterval)[self uptime];
        NSString *sinceNow = [NSString stringWithFormat:@"%f",timer];
         
        NSUserDefaults *UserDefaults = [NSUserDefaults standardUserDefaults];
        //存儲登錄時獲取的服務器時間
        [UserDefaults setObject:serverTime forKey:SWServerTime];
        //存儲登錄時獲取的待機時長
        [UserDefaults setObject:sinceNow forKey:SWSinceNow];
    
}

 

 

 3.獲得當前的時間(以服務器時間為基準)

 

+ (NSDate *)dateOfNow
{
    NSDateFormatter *formatter = [[NSDateFormatter alloc]init];
    [formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
     
    NSUserDefaults *UserDefaults = [NSUserDefaults standardUserDefaults];
    //取出登錄時獲取的服務器時間
    NSString * serverText = [UserDefaults objectForKey:SWServerTime];
    NSDate *FirstServer = [formatter dateFromString:serverText];
     
    NSString *firstText = [UserDefaults objectForKey:SWSinceNow];
    CGFloat first = firstText.floatValue;
    NSTimeInterval timer = (NSTimeInterval)[self uptime];
     
    CGFloat second = (CGFloat)timer;
     
    //差值
    CGFloat finaly = second - first;
    NSTimeInterval interval = (NSTimeInterval)finaly;
     
    //最後的時間
    NSDate *finalyDate = [FirstServer dateByAddingTimeInterval:interval];
    return finalyDate;
}

 

 4.深度探討

 

   為什麼獲取待機時間不用SystemUptime這種方法?

答案 :SystemUptime這種獲取待機時間的方式在我們設備深度睡眠的時候,獲取的值會有誤差,而上面我所用的方法不會。親測!!!

 

   如果我要獲取手機的開機時間,怎麼辦?

答案 :

 

  

/**
 *  獲得開機時間
 */
+ (NSString *)getUpTime{
    NSString * proc_useTiem;
    int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, 0};
    size_t miblen = 4;
    size_t size;
    //返回0,成功;返回-1,失敗
    int st = sysctl(mib, miblen, NULL, &size, NULL, 0);
    
    struct kinfo_proc * process = NULL;
    struct kinfo_proc * newprocess = NULL;
    do
    {
        size += size / 10;
        newprocess = realloc(process, size);
        if (!newprocess)
        {
            if (process)
            {
                free(process);
                process = NULL;
            }
            return nil;
        }
        process = newprocess;
        st = sysctl(mib, miblen, process, &size, NULL, 0);
        
    }
    while (st == -1 && errno == ENOMEM);
    if (st == 0)
    {
        if (size % sizeof(struct kinfo_proc) == 0)
        {
            int nprocess = size / sizeof(struct kinfo_proc);
            if (nprocess)
            {
                for (int i = nprocess - 1; i >= 0; i--)
                {
                    @autoreleasepool{
                        
                        //進程的時間
                        double t = process->kp_proc.p_un.__p_starttime.tv_sec;
                        double s = process->kp_proc.p_un.__p_starttime.tv_usec;
                        double finaly = t + s *0.000001;
                        //將其轉為具體時間
                        proc_useTiem = [self timeWithBoot:finaly];
                    }
                    
                }
                free(process);
                process = NULL;
                return proc_useTiem;
                
            }
        }
    }
    return nil;
}

 

 

 

/**
 *  轉為具體時間
 */
+ (NSString *)timeWithBoot:(double)interval
{
    NSDateFormatter *format = [[NSDateFormatter alloc]init];
    format.timeZone = [NSTimeZone timeZoneWithName:@"shanghai"];
    [format setDateStyle:NSDateFormatterMediumStyle];
    [format setTimeStyle:NSDateFormatterShortStyle];
    //註意先後順序
    [format setDateFormat:@"yyyy-MM-dd HH:mm:ss.SSS"];
    NSDate *date = [NSDate dateWithTimeIntervalSince1970:interval];
    NSString *bootTime = [format stringFromDate:date];
    return bootTime;
}

 

 

發佈留言