4

ich habe:Warum Schleifenvariable werden `nil` nach Schleife

NSDictionary* server; 

for (server in self.servers) 
{ 
    if (<some criterium>) 
    { 
     break; 
    } 
} 

// If the criterium was never true, I want to use the last item in the 
// the array. But turns out that `server` is `nil`. 

Der Loop-Block ändert sich nie server.

servers ist ein NSMutableArray mit Wörterbüchern, eine Eigenschaft, die während der Schleife nicht geändert wird.

Warum hat server den Wert nil, nachdem die Schleife beendet wurde?

War das erste Mal, dass ich eine solche Variable nach der Schleife verwendet. Ohne zu viel zu denken, nahm ich es wie funktionieren würde (in den alten C Tagen):

int i; 
for (i = 0; i < n; i++) 
{ 
    ... 
} 
+5

Die Schleife muss etwas beendet werden, wenn also die Dinge in self.servers ausgehen, um sie dem Server für die Schleife zuzuweisen, ist nil der logische Endwert. –

+1

Ist die zweite "Server" -Variable eine separate Deklaration - das heißt, ist sie nur für den For-Block (dh das Original wurde nie zugewiesen)? –

+2

Diese Funktion ist nützlich, wenn Sie nach einem bestimmten Objekt in einer Sammlung suchen und die Schleife bei der Suche "unterbrechen". Wenn die Schleifenvariable mit dem Wert 'nil' endet, hat die Schleife das gewünschte Objekt nicht gefunden. – user3386109

Antwort

7

Die Sprache definiert dass die Schleifenvariable wird wird auf Null gesetzt, wenn die Schleife beendet wird. Die Sprache besagt nicht, dass die Schleifenvariable den letzten Wert hat, ganz im Gegenteil.

Hinter den Kulissen gibt es einen sehr guten Grund dafür. Die schnelle Iteration nimmt Annahmen über die zugrunde liegenden Daten vor. Wenn Sie beispielsweise über ein veränderbares Array iterieren, wird das Array möglicherweise nicht während der Iteration geändert. Die schnelle Iteration ist unter anderem deshalb schnell, weil sie die Schleifenvariable nicht speichert und freigibt. Stattdessen stützt es sich auf das zugrunde liegende Objekt (z. B. ein Array), um eine Referenz zu halten.

Sobald die Schleife beendet ist, gibt das zugrunde liegende Objekt keine Garantien mehr. Das Array könnte verschwinden oder das zuletzt verwendete Array-Element könnte gelöscht werden. Also muss der Compiler entweder die Variable behalten oder auf null setzen. Die Einstellung auf Null ist schneller.

+5

Dies gilt nur, wenn die schnelle Enumeration die gesamte Liste durchläuft. Wenn die Schleife früh bricht, hat die Schleifenvariable (die vor der Schleife deklariert wurde) den letzten Wert. Es wird nur auf "Null" gesetzt, wenn die Schleife vollständig ausgeführt wird. – rmaddy

5

Die Variablen in einem for-loop verwendet wird immer nil wenn Schleifenende (außer wenn die Schleife mit break Aussage gebrochen ist, wie von @rmaddy gezeigt).

Eine weitere Möglichkeit für die Schleife, die Missverständnisse vermeiden wird, ist:

for (NSDictionary* server in self.servers) 
{ 
    //... server is not nil 
} 
//here server doesn't exist (out of scope) 

Wenn Sie einen Wert von self.servers in einem var außerhalb der Schleife speichern möchten, müssen Sie dies tun:

NSDictionary* serverSave; 

for (NSDictionary* server in self.servers) 
{ 
    serverSave = server; 
} 
//here you can use serverSave, which will contain the last value of self.servers 

Hoffe das hilft.

+2

Nein, nach der Schleife wird es nicht immer "nil" sein. Dies gilt nur, wenn die Schleife die gesamte Liste durchlaufen darf. Wenn die Schleife vorzeitig beendet wird (z. B. über "break"), verweist die Variable auf den Wert, den sie beim Beenden der Schleife hatte. – rmaddy

-1

Es ist Null nach der Schleife, weil Objective-C mit ARC es nicht erfüllt (siehe Value of loop variable after "for in" loop in Objective C).

So, wenn Sie erhalten bis Ende:

NSDictionary* server; // server is nil here 

for (server in self.servers) 
{ 
    ... // Does not set server to nil. 
} 

server wird gleich Null sein.

Wenn Sie für einen bestimmten Wert suchen, können Sie dies tun:

NSDictionary *dict; 

for (NSDictionary* server in self.servers) 
{ 
    if (server == whatever you want){ 
     dict = server; 
     break; 
    } 
} 

Oder bekommen nur den letzten Wert:

NSDictionary *dict; 

for (NSDictionary* server in self.servers) 
{ 
    dict = server; 
} 
+1

In den letzten beiden Beispielen gibt es keinen Grund, 'server' vor der Schleife zu deklarieren. Es ist tatsächlich verwirrender, dies zu tun. – rmaddy

+0

@rmaddy, ich habe es einfach so gehalten, wie es in der Frage war. – WMios

Verwandte Themen