2013-10-15 9 views
19

Dopo un tutorial su treehouse, vedo questo popolare messaggio di avviso Object-C in XCode.conversione implicita c perde la precisione intera 'NSUInteger'

La mia funzione pulsante

- (IBAction)buttonPressed:(UIButton *)sender { 
    NSUInteger index = arc4random_uniform(predictionArray.count); 
    self.predictionLabel.text = [predictionArray objectAtIndex:index]; 
} 

vedo sulla linea NSUInteger, ho pochi pochi dei stackoverflows simili e sembrano parlare di 32bit vs numeri a 64 bit e il tipo di getto, ma non sapete come per farlo qui?

mio predictionArray

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 
    predictionArray = [[NSArray alloc] initWithObjects: 
        @"It is certain", @"It is decidely so", @"All signs say YES", @"The stars are not aligned", 
        @"My reply is no", 
        @"It is doubtful", 
        @"Better not tell you now", 
        @"Concentrate and ask again", 
        @"Unable to answer now", nil]; 
// Do any additional setup after loading the view, typically from a nib. 
} 

enter image description here

risposta

67

È possibile sopprimere in modo sicuro l'avviso con un cast.

NSUInteger index = arc4random_uniform((uint32_t) predictionArray.count); 

Non è sempre sicuro per sopprimere avvertimenti, in modo da non andare gettando le cose per sbarazzarsi delle avvertenze fino a capire se l'operazione è sicuro.

Che cosa sta succedendo qui è che NSUInteger è, sulla piattaforma, un typedef per un tipo intero a 64 bit. Non è sempre 64 bit, solo su alcune piattaforme. Il compilatore ti avverte che alcuni di questi bit vengono gettati via. Se sai che questi bit non sono importanti, puoi semplicemente usare un cast.

In questo caso, il risultato è che index sarà sempre inferiore a 2 -1. Se è persino possibile che predictionArray contenga 2 o più elementi, il tuo programma ha un errore e dovrai costruire una versione a 64 bit di arc4random_uniform(). È possibile garantire questo con il seguente codice:

assert(predictionArray.count <= (uint32_t) -1); 
+0

Hmm, ho appena provato questo, ma sempre lo stesso avvertimento. Quindi, come faccio a fondere NSUInteger? Cosa significa '(NSUInteger)'. O forse, cosa più importante, di cosa mi sta avvertendo? –

+0

@LeonGaban: Ho inserito il cast nel posto sbagliato. –

+0

Grazie! Sto ancora cercando di capire questo, quindi 'NSUInteger' è sempre un int a 32 bit? Ho provato a lanciarlo come 64 bit e ho ottenuto lo stesso errore. Quel po 'di cose è nuovo per me, non ho mai dovuto imbattermi prima di –

11

Come per il mio commento, arc4random_uniform() prende in, e ritorna, un u_int32_t, un intero senza segno che è sempre 32 bit, indipendentemente dalla architettura target. Tuttavia, predictionArray.count restituisce un NSUInteger, che è typedef d in modo diverso per i sistemi a 32 e 64 bit; è 32 bit (unsigned int) su un sistema a 32 bit e 64 bit (unsigned long) su un sistema a 64 bit. Se stai utilizzando un sistema a 64 bit, passare a un valore a 64 bit da NSUInteger a una funzione che prevede un numero intero a 32 bit farà sì che il compilatore si lamenti che stai buttando via i bit.

+0

Grazie per la spiegazione, quindi se invio un numero a 32 bit in una funzione/metodo a 64 bit rallenta il programma? O sta solo dicendo che potrei essere più efficiente. Esiste una versione a 64 bit di 'arc4random_uniform()'? O dovrei semplicemente usare 'u_int32_t' molto? –

+1

@LeonGaban Un importo non percepibile, se non del tutto. Il tuo numero a 32 bit deve essere esteso per diventare 64-bit; se non è firmato, verrà automaticamente esteso con 0 e, se è firmato e negativo, verrà esteso con 1 secondo. Non è davvero un problema. Tuttavia, se si tenta di passare un numero a 64 bit in una funzione a 32 bit, parti del numero possono essere espulse (la funzione ottiene solo i 32 bit inferiori) e il compilatore si lamenta (ecco perché è necessario assicurati che sai cosa stai facendo con un cast). –

+0

@LeonGaban Sfortunatamente, non esiste una versione a 64 bit delle funzioni di 'arc4random *', ma continuate a lanciarvi in ​​esse e sarete a posto. Mi raccomando di non usare 'u_int32_t' ovunque perché è, per definizione, a 32 bit. 'NSUInteger' ha il vantaggio di essere' typedef'd per te da Apple per abbinare la piattaforma di destinazione, in modo che tu possa sempre usarlo e sapere che stai facendo le cose in modo efficiente (non vuoi limitare arbitrariamente la dimensione del tuo dati a meno che non abbia senso ed è necessario). –

Problemi correlati