2012-07-10 19 views
24

Sto provando a progettare un sistema in cui si verificano eventi in tempo reale e voglio sincronizzarli con un orologio. [NSDate date] normalmente sarebbe ok ma l'utente potrebbe cambiarlo e imbrogliare il sistema. Tutto ciò di cui ho bisogno è un orologio da cui posso prendere tempi relativi (ad esempio un contatore a 64 bit) - Non ho bisogno del tempo assoluto (o dell'ora del giorno, ecc.).C'è un orologio in iOS che può essere utilizzato che non può essere modificato dall'utente

C'è una tale API che posso usare?

MODIFICA: Vorrei anche aggiungere che questo orologio deve essere persistente per le sessioni dell'applicazione.

+0

La regola generale è: "Se è sul dispositivo dell'utente, può pasticciare con essa." Questo potrebbe non essere vero al 100%, ma è abbastanza vicino. – Almo

+0

Tuttavia, deve esserci un orologio persistente di basso livello (anche se inaccessibile tramite API pubbliche). In caso contrario, come fa il dispositivo a sapere quando è acceso? Se potessi attingere a ciò, potresti almeno ottenere secondi relativi tra le sessioni. –

+0

Il dispositivo potrebbe trascorrere il tempo trascorso tra l'ultimo arresto e questo avvio, ma una volta avviato, può essere modificato e al momento dell'avvio dell'app tutte le scommesse sono disattivate. – Almo

risposta

6

Se tutto ciò che serve è un orologio per misurare gli eventi come aumenti monotonicamente, si potrebbe semplicemente ottenere l'uptime del sistema corrente a clock_gettime(CLOCK_MONOTONIC). Se il riavvio del dispositivo è un problema, basta salvare l'ultimo valore utilizzato e al prossimo avvio utilizzare l'ultimo valore salvato come offset. Il problema qui potrebbe essere che se effettivamente spengono il dispositivo, non contano quella volta. Ma se sei preoccupato per l'utente che accelera il tempo, non può farlo, solo rallentarlo.

+1

Esistono documenti per 'clock_gettime (CLOCK_MONOTONIC)'? Ho trovato [questo] (http://www.qnx.com/developers/docs/6.5.0/index.jsp?topic=%2Fcom.qnx.doc.neutrino_lib_ref%2Fc%2Fclock_gettime.html). Ho provato a includere/importare '', ma Xcode ancora non riconosce 'CLOCK_MONOTONIC' e mi accusa di una definizione implicita di' clock_gettime() '. – JohnK

+0

@EdMarty c'è un modo per scoprire se il dispositivo è stato riavviato? –

+0

Non c'è modo di essere * assolutamente * certi senza tenere traccia del tempo usando una fonte esterna (e anche allora, man-in-the-middle, blah, blah, blah). Detto questo, è possibile tenere traccia di quanto tempo il dispositivo è stato in esecuzione dal momento dell'avvio del dispositivo (utilizzando una chiamata sysctl esoterica). Se è inferiore, allora sai per certo che è stato resettato dall'ultima volta che hai controllato. Nota: non si desidera utilizzare mach_absolute_time(), poiché in realtà si interrompe mentre il dispositivo è in modalità sleep. Ottenere il tempo di avvio: http://stackoverflow.com/questions/10331020/get-the-boot-time-in-objective-c –

1

L'unica idea che posso pensare è quella di utilizzare un server NTP per ottenere l'orologio, ma ciò richiederebbe la connettività di rete.

+0

Sì, speravo di evitarlo. – Cthutu

+0

E un utente abbastanza determinato da falsificare l'ora per imbrogliare potrebbe anche falsificare il tuo server NTP. – JeremyP

+3

Certo che potrebbero, ma si tratta di un significativo salto di sofisticazione rispetto alla confusione con le impostazioni di data/ora nei pannelli di controllo utente. Ho amici che non sono il minimo tecnico che hanno capito che possono imbrogliare i giochi in quel modo (o forse ne leggono online, qualunque cosa) ma è davvero facile da fare. Queste stesse persone non avrebbero idea di cosa NTP fosse molto meno avere la motivazione o la capacità di falsificare un server, anche se è facile per un hacker esperto. – Suboptimus

3

Quello che so, che non esiste nessun altro metodo per ottenere l'ora corretta. Vorrei usare NTP.

Network Time Protocol (NTP) è un protocollo di rete per sincronizzare gli orologi dei sistemi informatici su reti dati a latenza variabile a commutazione di pacchetto. Più: http://en.wikipedia.org/wiki/Network_Time_Protocol

In un progetto che ho intenzione di usare NTP (domani i quess), ma ho già fatto qualche ricerca:

iOS libreria:https://github.com/jbenet/ios-ntp - Note Autore: L'implementazione non è un rigoroso come descritto in quelle RFC poiché l'obiettivo era quello di migliorare l'accuratezza del tempo con in un secondo, non in frazioni di millisecondi.

Per guardare progetto non commerciale on: www.packages.ubuntu.com/source/lucid/ntp

libreria C: www.hillstone-software.com/hs_ntp_details.htm

Documentazione: www.nist.gov/pml/div688/grp40/its.cfm

5

Penso che mach_absolute_time() possa essere quello che vorrai. C'è un bel po 'di informazioni qui: http://developer.apple.com/library/mac/#qa/qa1398/_index.html

È fondamentalmente un contatore del numero di zecche da quando il dispositivo è partito. Questo verrà ripristinato al riavvio ma a parte questo è un contatore monotonicamente crescente.

è possibile mantenere l'ultimo valore del contatore intorno e trattare con esso se il contatore è diminuita dall'ultima volta (il dispositivo è stato riavviato). In questo caso è possibile aggiungere l'ultimo valore noto al valore corrente per ottenere un limite inferiore del tempo trascorso, tutto quello che ci si perde è il tempo che intercorre tra l'ultima sessione e il dispositivo di arresto, si dovrebbe tenere il tempo tra il riavvio e la prossima sessione però.

+0

Ha bisogno di un orologio persistente attraverso le sessioni, quindi non sarà di aiuto. – Almo

+0

mach_absolute_time() viene ripristinato solo al riavvio del dispositivo. – hypercrypt

+0

Il contatore potrebbe non essere diminuito se si immagina lo scenario in cui l'utente reimposta l'iphone, riproduce il gioco e lo arresta 5 minuti dopo, quindi reimposta nuovamente l'iphone e riproduce il gioco dopo 5 minuti. Ma sembra essere il metodo più affidabile - vorrei solo perdere tempo ma non accelerare. – Cthutu

9

Il numero monotonicamente crescente in aumento su un iPhone è mach_absolute_time() che è un conteggio dei tick della CPU dall'ultimo riavvio. Se desiderate in pochi secondi, per qualsiasi motivo, è più facilmente recuperato con CACurrentMediaTime().

Usando questo per creare un "always-incremento" è abbastanza facile. Al primo avvio, memorizza il valore corrente dove preferisci. Quando si esce, e periodicamente, salva l'offset da tale valore.Al riavvio, controllare il valore corrente; se è inferiore al precedente valore di base, sostituisci il valore di base (c'è stato un riavvio).

Tutto ciò, ovviamente, può essere cancellato rimuovendo l'app a meno che non si memorizzi qualcosa sul server.

Si noti che questo non può essere utilizzato come una forte misura di sicurezza. Non c'è modo di impedire a un utente autorizzato di falsificare richieste. Quindi, a seconda di cosa intendi con "ingannare il sistema", potrebbe non essere un problema risolvibile. Il meglio che puoi fare è avere una costante attenzione alla ricerca di hack e di trattare con loro.

+0

solo per notare, controllando se il valore è inferiore non dice per certo c'è stato un riavvio o meno. L'utente potrebbe essere riavviato, quindi ha aspettato più dell'ultimo tick registrato. – Gukki5

6

Sto usando questo nella nostra app

+ (NSDate *) getAWSDate 
{ 
    NSDate *today = nil; 
    NSString *dateString = nil; 

    NSString *awsURL = @"http://s3.amazonaws.com"; 
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:awsURL]]; 
    [request setHTTPMethod:@"HEAD"]; 

    NSHTTPURLResponse *response; 
    [NSURLConnection sendSynchronousRequest:request returningResponse:&response error: NULL]; 

    if ([response respondsToSelector:@selector(allHeaderFields)]) { 
     dateString = [[response allHeaderFields] objectForKey:@"Date"]; 
     dateString = [dateString stringByReplacingOccurrencesOfString:@"GMT" withString:@"+0000"]; 
     NSDateFormatter *df = [[NSDateFormatter alloc] init]; 
    df.dateFormat = @"EEE, dd MMM yyyy HH:mm:ss z"; 
    df.locale = [[[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"] autorelease]; 
    df.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"GMT"]; 
    today = [df dateFromString:dateString]; 
    [df release];  
    }   
    return today; 
} 
+0

Grazie per il codice. Lo userò se deciderò di usare un server orario. Al momento sto cercando di evitare la connettività di rete. – Cthutu

+0

Cosa strana. Sto ottenendo "(null)" su iPad Air con questo codice. Con un vecchio iPad (3a gen) e un simulatore, funziona! Entrambi con iOS 8.0.2. Qualche idea? – tomDev

+0

Come è successo quando S3 è andato giù questa settimana? –

Problemi correlati