2014-07-02 8 views
5

Cercando di chiamare dispatch_time a Swift sta facendo la mia testa in, ecco perché:Come si trasmette un UInt64 a un Int64?

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 10 * NSEC_PER_SEC), dispatch_get_main_queue(), { 
      doSomething() 
      }) 

genera l'errore: "Impossibile trovare un sovraccarico di '*' che accetta gli argomenti forniti".

NSEC_PER_SEC è un tempo UInt64 così per alcuni esperimenti:

let x:UInt64 = 1000 
let m:Int64 = 10 * x 

Risultati nella stessa errore come sopra

let x:UInt64 = 1000 
let m:Int64 = 10 * (Int64) x 

Risultati in "dichiarazioni consecutive su una linea devono essere separati da ';' "

let x:UInt64 = 1000 
let m:Int64 = 10 * ((Int64) x) 

Risultati in" Expected '' separatore"

let x:UInt64 = 1000 
let m:Int64 = (Int64)10 * (Int64) x 

Risultati in "dichiarazioni consecutivi su una linea devono essere separati da ';'"

ecc ecc

Accidenti a te compilatore Swift, mi arrendo. Come faccio a trasmettere un UInt64 a Int64 e/o come usi dispatch_time in swift?

risposta

1

La trasmissione di un UInt64 a un non è sicura poiché un UInt64 può avere un numero superiore a Int64.max, che provocherà un overflow.

Ecco un frammento per convertire un UInt64 a Int64 e viceversa:

// Extension for 64-bit integer signed <-> unsigned conversion 

extension Int64 { 
    var unsigned: UInt64 { 
     let valuePointer = UnsafeMutablePointer<Int64>.allocate(capacity: 1) 
     defer { 
      valuePointer.deallocate(capacity: 1) 
     } 

     valuePointer.pointee = self 

     return valuePointer.withMemoryRebound(to: UInt64.self, capacity: 1) { $0.pointee } 
    } 
} 

extension UInt64 { 
    var signed: Int64 { 
     let valuePointer = UnsafeMutablePointer<UInt64>.allocate(capacity: 1) 
     defer { 
      valuePointer.deallocate(capacity: 1) 
     } 

     valuePointer.pointee = self 

     return valuePointer.withMemoryRebound(to: Int64.self, capacity: 1) { $0.pointee } 
    } 
} 

Questa interpreta semplicemente i dati binari di UInt64 come Int64, ossia numeri maggiori di Int64.max saranno negativi a causa del bit di segno al bit più significativo del numero intero a 64 bit.

Se si desidera solo numeri interi positivi, è sufficiente ottenere il valore assoluto.

EDIT: A seconda del comportamento, è possibile ottenere il valore assoluto, o:

if currentValue < 0 { 
    return Int64.max + currentValue + 1 
} else { 
    return currentValue 
} 

Quest'ultima opzione è simile a nudo il bit di segno. Es:

// Using an 8-bit integer for simplicity 

// currentValue 
0b1111_1111 // If this is interpreted as Int8, this is -1. 

// Strip sign bit 
0b0111_1111 // As Int8, this is 127. To get this we can add Int8.max 

// Int8.max + currentValue + 1 
127 + (-1) + 1 = 127 
4

Prova questo:

let x:UInt64 = 1000 // 1,000 
let m:Int64 = 10 * Int64(x) // 10,000 

o anche:

let x:UInt64 = 1000 // 1,000 
let m = 10 * Int64(x) // 10,000 
let n = Int64(10 * x) // 10,000 
let y = Int64(x) // 1,000, as Int64 (as per @Bill's question) 

Non è tanto fusione come l'inizializzazione con un tipo distinto ...

+0

Grazie, facile una volta che sai – Gruntcakes

+0

Infatti! :) - è un cambio di mente ... – Grimxn

+0

Invece di moltiplicare per 10, puoi semplicemente moltiplicare per uno? – Bill

3

È possibile "cast" tra i diversi integer tipi inizializzando un nuovo intero con il tipo desiderato:

let uint:UInt64 = 1234 
let int:Int64 = Int64(uint) 

probabilmente non è un problema nel tuo caso particolare, ma vale la pena notare che i diversi tipi interi hanno differenti gamme, e si può finire con fuori portata si blocca se si tenta di convertire tra interi di diverse tipologie:

let bigUInt:UInt64 = UInt64(Int64.max) - 1  // 9,223,372,036,854,775,806 
let bigInt:Int64 = Int64(bigUInt)    // no problem 

let biggerUInt:UInt64 = UInt64(Int64.max) + 1 // 9,223,372,036,854,775,808 
let biggerInt:Int64 = Int64(biggerUInt)   // crash! 

Ogni tipo integer ha .max e .min classe proprietà che è possibile utilizzare per i campi di controllo:

if (biggerUInt <= UInt64(Int64.max)) { 
    let biggerInt:Int64 = Int64(biggerUInt)  // safe! 
} 
1

soluzione migliore per la conversione:

UInt64 Int64_2_UInt64(Int64 Value) 
{ 
    return (((UInt64)((UInt32)((UInt64)Value >> 32))) << 32) 
     | (UInt64)((UInt32)((UInt64)Value & 0x0ffffffff));   
} 

Int64 UInt64_2_Int64(UInt64 Value) 
{ 
    return (Int64)((((Int64)(UInt32)((UInt64)Value >> 32)) << 32) 
     | (Int64)((UInt32)((UInt64)Value & 0x0ffffffff)));   
} 
+0

forse più veloce, ma meglio ... sicuramente sembra dannatamente hardcore ai miei occhi xD – joe

0

soluzione semplice per Swift 3 è una funzione incorporata che si occupa di overflow e gestione del buffer.

var a:UInt64 = 1234567890 
var b:Int64 = numericCast(a) 
Problemi correlati