4

後nil`になるん:はなぜループ変数は `私が持っているループ

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`. 

ループブロックがserverを変更することはありません。

serversは、辞書を持つNSMutableArrayです。このプロパティはループ中に変更されません。

serverは、ループが終了した後に値がnilになるのはなぜですか?

ループの後でこのような変数を初めて使用しました。あまり考えずに、私はそれが(旧Cの日に)のように働くだろうと想定:

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

ループは幾分か終了しなければならないので、ループのためにサーバに割り当てるためにself.serversのものがなくなると、nilは論理的な終了値になります。 –

+1

2番目の "server"変数は別の宣言ですか?つまり、forブロックのみにスコープが設定されています(元のものは割り当てられていないことを意味します)。 –

+2

この機能は、コレクション内の特定のオブジェクトを検索しているときにループを「中断」する場合に便利です。ループ変数の値が 'nil'で終わると、ループは目的のオブジェクトを見つけられませんでした。 – user3386109

答えて

7

言語をループ変数がされることを定義しますループが終了するとnilに設定されます。言語は、ループ変数が最後の値を持つと述べているわけではありません。

背後には非常に良い理由があります。高速反復では、基礎となるデータについての前提があります。たとえば、変更可能な配列を反復処理する場合、反復処理中は配列が変更されないことがあります。ループ変数を保持したり解放したりしないため、高速反復は高速です。代わりに、参照を保持するために基底のオブジェクト(配列など)に依存します。

一度ループが終了すると、その基本オブジェクトはもはや保証を与えません。配列がなくなるか、最後に使用された配列要素が削除される可能性があります。したがって、コンパイラは変数を保持するか、変数をnilに設定する必要があります。 nilに設定する方が速いです。

+5

これは、高速列挙がリスト全体を反復処理を完了した場合にのみ当てはまります。ループが早期に中断した場合、ループ変数(ループの前に宣言された)は最後の値を持ちます。ループが完全に実行されている場合にのみ 'nil'に設定されます。 – rmaddy

5

for-loopで使用される変数は常に、ループがbreak文で切断された場合を除いて(nilときループ終了となります@rmaddyが指すように)。誤解を避けることができますあなたのforループ

もう一つの方法は次のとおりです。

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

あなたはループの外でVarのself.serversの値を保存したい場合は、この操作を行う必要があるでしょう:

NSDictionary* serverSave; 

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

これが役に立ちます。

+2

いいえ、ループの後で常に 'nil'になるとは限りません。これは、ループがリスト全体を反復することが許可されている場合にのみ当てはまります。ループが早く終了した場合(例えば、 'break'を介して)、変数はループが終了したときの値を参照します。 – rmaddy

-1

ARCを使用したObjective-Cがそれを埋め込んでいるため、ループの後にはnil(Value of loop variable after "for in" loop in Objective C参照)です。

は、このようにあなたが最後に到達したとき:

NSDictionary* server; // server is nil here 

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

server nilになります。あなたが特定の値を探している場合

あなたはこれを行うことができます。

NSDictionary *dict; 

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

それとも最後の値を取得します

NSDictionary *dict; 

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

最後の2つの例では、ループの前に 'server'を宣言する理由はありません。実際にそうするのはもっと混乱します。 – rmaddy

+0

@rmaddy、私はちょうどそれが質問にあった方法と同じままにしていた。 – WMios

関連する問題