2

私は最近、自動解放されたオブジェクトを返すかどうかに関するこの議論に参加しました。lastObject私はいつもそれがそうだと思っていましたし、問題があったこともありませんでしたが、考えてみると、ほとんどの場合、この方法を使用していて、私のコレクションは参照よりも長生きしていました。参照、コードは正常に機能したはずです。したがって、戻り値の自動解放された性質に関して(いくつかのSOの回答に基づいて)間違っていたようですが、Appleのドキュメントでそれについて何かを見つけようとしましたが、失敗しました。

ApplelastObjectは、返されたオブジェクトを自動解放するかどうかを文書化しましたか? もしそうなら、それはどこに文書化されていますか? そして、これが真実であることが判明した場合、なぜ彼らはこのようにしたのでしょうか? 上記の議論で得た答えは私には意味がありません.コレクションはオブジェクトを保持して自動解放することができましたか? このように、オブジェクトは実行ループの最後でも有効です。

4

5 に答える 5

7

明示的に文書化されていませんlastObjectが、 と同じ動作をする可能性がありobjectAtIndex:ます。objectAtIndex:そうではなく retainautoreleaseこのドキュメントに従って返されるオブジェクト:使用しているオブジェクトの割り当て解除を引き起こすことを回避します

オブジェクトが基本的なコレクション クラスの 1 つから削除されると、(自動解放ではなく) 解放メッセージが送信されます。コレクションが削除されたオブジェクトの唯一の所有者であった場合、削除されたオブジェクト (例の heisenObject ) はすぐに割り当て解除されます。

(私のものを強調)

同じドキュメント ページの次の例を検討してください。

heisenObject = [array objectAtIndex:n];
[array removeObjectAtIndex:n];
// heisenObject could now be invalid.

メモリ管理の観点では、配列全体を解放することはすべてのオブジェクトを削除することと同じであるため、返されたオブジェクトが特定の状況下で実際に割り当て解除されない場合でも、実行ループの最後まで有効であるとは期待できません (例:リテラル文字列、シングルトン、オブジェクトへのその他の参照など)。

于 2012-12-31T18:07:23.713 に答える
5

オブジェクトを自動解放する場合-[NSArray lastObject]、「この動作に依存できるように、オブジェクトを自動解放するように文書化されていますか?」と尋ねるのが妥当です。</p>

ただし、オブジェクトを自動解放しない場合-[NSArray lastObject]は、動作が文書化されているかどうかを尋ねる必要はありません返されたオブジェクトが配列の割り当てまたは割り当て解除後も確実に存続するようにする場合は、返されたオブジェクトを保持する必要があります。removeLastObjectこれを保持しないと、プログラムが正しく動作しなくなります。ドキュメントに何が書かれているかどうかは問題ではありません。この場合、プログラムが正しく動作することを保証する唯一の方法は、オブジェクトを保持することです。lastObjectまた、将来オブジェクトを自動解放するように変更された場合でも、プログラムは正しく動作します。

したがって、他に何も知らずに、オブジェクトを保持する必要があります。

しかし、私たちは別のことを知ることができます。メソッドを逆アセンブルして、-[NSArray lastObject]自動解放されるかどうかを調べることができます。そうすれば、ドキュメンテーションの内容を尋ねる必要があるかどうかがわかります。

この-[NSArray lastObject]メソッドは、CoreFoundation フレームワークに実装されています。Hopperを使用して OS X 10.8 (Mountain Lion) 64 ビット バージョンを逆アセンブルしました。

75e30 55              push       rbp
75e31 4889E5          mov        rbp, rsp
75e34 53              push       rbx
75e35 50              push       rax
75e36 4889FB          mov        rbx, rdi
75e39 488D3530971800  lea        rsi, qword [ds:objc_msg_count] ; @selector(count)
75e40 4889DF          mov        rdi, rbx
75e43 FF1527971800    call       qword [ds:objc_msg_count]     ; @selector(count)
75e49 4885C0          test       rax, rax
75e4c 7509            jne        0x75e57

75e4e 31C0            xor        eax, eax
75e50 4883C408        add        rsp, 0x8
75e54 5B              pop        rbx
75e55 5D              pop        rbp
75e56 C3              ret        

75e57 48FFC8          dec        rax           ; XREF=0x75e4c
75e5a 488B0D1F971800  mov        rcx, qword [ds:objc_msg_objectAtIndex_] ; @selector(objectAtIndex:)
75e61 488D3518971800  lea        rsi, qword [ds:objc_msg_objectAtIndex_] ; @selector(objectAtIndex:)
75e68 4889DF          mov        rdi, rbx
75e6b 4889C2          mov        rdx, rax
75e6e 4883C408        add        rsp, 0x8
75e72 5B              pop        rbx
75e73 5D              pop        rbp
75e74 FFE1            jmp        rcx

x86 アセンブラーを話せる場合は、それを次の単純な Objective-C コードに変換できます。

- (id)lastObject {
    NSUInteger count = self.count;
    return count == 0 ? nil : [self objectAtIndex:count-1];
}

はオブジェクトを自動解放しないと文書化されているobjectAtIndexため、 の実際の実装ではオブジェクトが自動解放されないことがわかり-[NSArray lastObject]ます。

これは、ドキュメンテーションが何を言おうと関係ないことを意味します。プログラムを正しく動作させたい場合は、オブジェクトを保持する必要があります。

実装の詳細に頼るべきだと言っているわけではないことに注意してください。ドキュメントを探す価値があるかどうかを判断するために実装を使用しているだけです。

于 2012-12-31T19:48:51.277 に答える
3

autoreleased+1オブジェクトを返す実装に依存しないでください。明示的に文書化されNSArrayていて、自動解放されていることが明示的に述べられていない場合を除きます。これは実装定義であり、時間の経過とともに動作が変化する可能性があるためです。オブジェクトの有効期間を、それを返すオブジェクトの時間の長さを超えて延長する必要がある場合、または次の実行ループまで延長する必要がある場合は、それを行う必要がありますretain

たとえば、このlastObjectメソッドは、各フレームワーク バージョン間で以下の両方の実装を自由に切り替えることができます。2 番目の実装から最初の実装への切り替えは決して良い考えではありませんが、それでも可能であり、最後のオブジェクト、すべてのオブジェクトを削除するか、配列を解放する前に、最後のオブジェクトを保持していないコードを壊してしまいます。

//implementation 1
- (id)lastObject
{
    if(self.length < 1)
        return nil;

    return [self objectAtIndex:self.length - 1];
}
//implementation 2
- (id)lastObject
{
    if(self.length < 1)
        return nil;

    return [[[self objectAtIndex:self.length - 1] retain] autorelease];
}
于 2012-12-31T18:36:43.357 に答える
0

自動リリースされている場合は実装の詳細であり、確実に回答することはできません。

lastObject は、所有していないオブジェクトを返します。ココア メモリの命名規則に従って: 明示的に「新規またはコピーまたは割り当て」という名前のメソッド (IIRC の 3 つ) のみが新しいオブジェクトを返します。

参照: https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html

于 2012-12-31T17:53:06.413 に答える
-1

実際にはいいえ、なぜ彼らはオブジェクトを自動解放するのでしょうか?

呼び出すlastObjectことで、最後のオブジェクトを取得するだけです。それはまだ配列に保存されています。したがって、配列はオブジェクトを解放したり、オブジェクトを保持したりしないでください。

自動解放は、オブジェクトを作成し、場合によってはそれを変更し、それを別のオブジェクトに渡すことができる場合に役立ちます。

これは当てはまりません。配列内の最後のオブジェクトが何であるかを単に伝え、保持はそれを受け取るオブジェクトの仕事です。

于 2012-12-31T17:55:42.857 に答える