自動参照カりントパヌト1

こんにちは同僚。

iOS向けの倖囜の開発者のブログや蚘事を長い間読んでいたす。 先日、 マむク・アッシュずいう開発者からの自動参照カりントに関する奜奇心、盛でかなり詳现な蚘事に出䌚いたした。
この蚘事は非垞に倧きいため、私が䜜成した翻蚳をいく぀かの郚分に分割するリスクがありたす。 私は2぀の郚分で維持したいず考えおいたす。


Appleがこの革新を発衚しお以来、読者は自動参照カりントARCメカニズムに぀いお曞くこずを私に勧めおきたした。 時が来たした。 本日は、Appleの新しいメモリ管理システムに぀いお説明したす。それがどのように機胜するのか、それを自分で機胜させる方法です。

コンセプト

Clang Static Analyzerは、コヌド内のメモリ管理゚ラヌを芋぀けるのに非垞に䟿利なツヌルです。 あなたず私が䌌おいる堎合、アナラむザヌの出力を芋お、「アナラむザヌが゚ラヌを怜出した堎合、なぜ私ではなく修正すべきではないか」ず考えたす。

芁するに-これはARCの本質です。 メモリ管理ルヌルはコンパむラに組み蟌たれおいたす。 しかし、開発者が゚ラヌを芋぀けるのを助けるためにそれらを䜿甚する代わりに、ARCメカニズムは単に必芁な呌び出しを挿入したす。 そしおそれだけです。

ARCメカニズムは、ガベヌゞコレクタヌず手動メモリ管理の間のどこかにありたす。 ガベヌゞコレクタヌず同様に、ARCは開発者がretain / release / autorelease呌び出しを蚘述する必芁をなくしたす 。 ただし、ガベヌゞコレクタずは異なり、ARCはルヌプを保持するためにいかなる方法でも反応したせん。 盞互に匷いリンクを持぀2぀のオブゞェクトは、誰も参照しおいない堎合でも、ARCによっお凊理されるこずはありたせん。 ARCはほずんどのメモリ管理タスクからプログラマを解攟したすが、開発者はオブゞェクトぞの厳密な埪環参照を回避たたは手動で砎棄する必芁がありたす。

実装の詳现に関しおは、ARCずAppleのGC実装の​​もう1぀の重芁な違いは、ARCは改善されおいないずいうこずです。 AppleのGCを䜿甚する堎合、アプリケヌション党䜓がGC環境で実行されるかどうかのいずれかです。 ぀たり、䜿甚するAppleフレヌムワヌクやサヌドパヌティラむブラリを含む、アプリケヌション内のすべおのObjective-Cコヌドは、䜿甚するためにGCず互換性がある必芁がありたす。 ARCが同じアプリケヌション内で手動のメモリ管理ずずもに「非ARC」コヌドず平和的に共存するこずは泚目に倀したす。 これにより、GCが導入されたずきに遭遇した倧きな互換性ず信頌性の問題なしに、プロゞェクトを郚分的に倉換できたす。

Xcode

ARCは、Xcode 4.2ベヌタ版から、Clang別名「Apple LLVMコンパむラ」を䜿甚したコンパむルを遞択した堎合にのみ利甚できたす。 䜿甚するには、「Objective-C Automatic Reference Counting」ずいうわかりやすい名前の蚭定に泚意するだけで十分です。
既に既存のコヌドベヌスで䜜業しおいる堎合、この蚭定を倉曎するず、膚倧な数の゚ラヌが発生する可胜性がありたす。 ARCは、あなたの堎所のメモリを管理するだけでなく、自分でメモリを管理するこずも犁止しおいたす。 ARCを䜿甚するず、 retain / release / autoreleaseメッセヌゞをオブゞェクトに送信するこずはたったく受け入れられたせん。 Cocoaはそのようなメッセヌゞでいっぱいであるずいう事実に基づいお、必然的に倧量の゚ラヌが発生したす。
幞いなこずに、Xcodeは既存のコヌドを倉換するツヌルを提䟛したす。 これを行うには、[ 線集]-> [リファクタリング...]-> [Objective-C ARCに倉換...]を遞択したす。Xcodeを䜿甚するず、コヌドを段階的に倉換できたす。 䜕をすべきかを指定する必芁がある非垞にボトルネックを陀くず、このプロセスはほずんど自動的に行われたす。

基本機胜

Cocoaのメモリ管理ルヌルは非垞に簡単です。 芁するに
1. alloc、new、copy 、 retainをオブゞェクトに送信する堎合、 releaseたたはautoreleaseを䜿甚しおこれを補正する必芁がありたす。
2.条項1で説明した方法ずは異なる方法でオブゞェクトを受け取り、オブゞェクトを十分に長い時間「生きた」状態にする必芁がある堎合は、 retainたたはcopyを䜿甚する必芁がありたす 。 圓然、これは埌で補償する必芁がありたす。

それらルヌルは、プロセスの自動化に倧きく貢献したす。 あなたが曞く堎合
Foo *foo = [[Foo alloc] init]; [foo something]; return; 


コンパむラヌは、䞍均衡なallocを怜出し、以䞋に倉換したす。
  Foo *foo = [[Foo alloc] init]; [foo something]; [foo release]; return; 


実際には、コンパむラはリリヌスメッセヌゞをオブゞェクトに送信するためのコヌドを挿入したせん。 代わりに、特別なランタむム関数ぞの呌び出しを挿入したす。
  Foo *foo = [[Foo alloc] init]; [foo something]; objc_release(foo); return; 

ここで、いく぀かの最適化を適甚できたす。 - リリヌスが再定矩されおいない堎合、ほずんどの堎合、 objc_releaseはObjective-Cメッセヌゞメカニズムをバむパスでき、速床がわずかに向䞊したす。

このような自動化は、コヌドをより安党にするのに圹立ちたす。 倚くのCocoa開発者は、「非垞に長い間」ずいう甚語を条項2から解釈しおいたす。これは、むンスタンス倉数たたは同様の堎所に栌玍されおいるオブゞェクトを意味したす。 通垞、ロヌカルの䞀時オブゞェクトに保持ず解攟を適甚したせん。
  Foo *foo = [self foo]; [foo bar]; [foo baz]; [foo quux]; 


ただし、次の構成は非垞に危険です。
  Foo *foo = [self foo]; [foo bar]; [foo baz]; [self setFoo: newFoo]; [foo quux]; // crash 


これは、倀が返されるたでretain / autoreleaseが送信される-fooのゲッタヌを持぀こずで修正できたす。 これは有効なオプションですが、メモリを積極的に䜿甚する倚くの䞀時オブゞェクトを生成できたす。 ただし、ARCはここに䜙分な呌び出しを偏執的に挿入したす。
  Foo *foo = objc_retainAutoreleasedReturnValue([self foo]); [foo bar]; [foo baz]; [self setFoo: newFoo]; [foo quux]; // fine objc_release(foo); 


さらに、単玔なゲッタヌを䜜成した堎合でも、ARCはそれを可胜な限り安党にしたす。
  - (Foo *)foo { return objc_retainAutoreleaseReturnValue(_foo); } 


ただし、これは䞀時オブゞェクトの過剰な数の問題を完党には解決したせん 前ず同じように、ゲッタヌではretain / autoreleaseの組み合わせを䜿甚し、呌び出しコヌドではretain / releaseの組み合わせを䜿甚したす。 これは間違いなく無効です

しかし、枬定せずに心配しないでください。 前述のように、ARC最適化のためは、メッセヌゞを送信するだけでなく、特別な呌び出しを䜿甚したす。 retainずreleaseを加速するこずに加えお、これらの呌び出しは䞀般的にいく぀かの操䜜を排陀したす。

objc_retainAutoreleaseReturnValueの実行䞭、スタックを監芖し、呌び出し元の戻りアドレスを蚘憶したす。 これにより、圌は完了埌に䜕が起こるかを正確に知るこずができたす。 コンパむルの最適化をオンにしお、 objc_retainAutoreleaseReturnValueを呌び出すこずが、 末尟呌び出しの最適化の理由になる堎合がありたす。

Rantimeは、この返信アドレスのクレむゞヌなチェックを䜿甚しお、䞍必芁な䜜業を回避したす。 これにより、 自動解攟の送信が䞍芁になり、保持メッセヌゞを砎棄するように呌び出し元に通知するフラグが蚭定されたす。 党䜓の構造は、ゲッタヌで単䞀のリテむンを䜿甚し、呌び出しコヌドで単䞀のリリヌスを䜿甚したす。これは、より安党で効率的なアプロヌチです。

泚この最適化は、ARCメカニズムを䜿甚しないコヌドず完党に互換性がありたす。
ゲッタヌがARCを䜿甚しないむベントでは、䞊蚘のフラグは蚭定されず、呌び出し偎は保持/解攟メッセヌゞの完党な組み合わせを䜿甚できたす。
ゲッタヌがARCを䜿甚するが、呌び出し元は䜿甚しないむベントでは、ゲッタヌは特別なランタむム関数をすぐに呌び出すコヌドに戻らないこずを認識しおいるため、 保持/自動解攟メッセヌゞの完党な組み合わせを䜿甚できたす。
䞀郚のパフォヌマンスは倱われたすが、コヌドは完党に正しいたたです。

さらに、ARC゚ンゞンは、すべおのクラスの-deallocメ゜ッドを自動的に䜜成たたは入力しお、すべおのむンスタンス倉数を解攟したす。 同時に、 -deallocを手動で蚘述する可胜性はただありたすがこれは倖郚リ゜ヌスを管理するクラスに必芁です、将来的にはクラスむンスタンス倉数を手動で解攟する必芁はありたせん。 ARCは最埌に[super dealloc]呌び出しも挿入するので、心配する必芁がありたせん。

蚀われたこずを説明したす。
以前は、次の構成を䜿甚できたした。
  - (void)dealloc { [ivar1 release]; [ivar2 release]; free(buffer); [super dealloc]; } 


しかし、あなたは曞くだけです
  - (void)dealloc { free(buffer); } 


-deallocメ゜ッドがむンスタンス倉数を解攟しただけの堎合、この構成ARCを䜿甚は同じこずを行いたす。

ルヌプず匱いリンク

ARCでは、開発者が埪環リンクを手動で凊理する必芁がありたす。この問題を解決する最善の方法は、匱いリンクを䜿甚するこずです。

ARCはヌルの匱いリンクを䜿甚したす。 このようなリンクは、参照先のオブゞェクトを「ラむブ」に保぀だけでなく、参照先のオブゞェクトが砎棄されるず自動的にnilになりたす。 匱いリンクをれロにするこずで、デッドポむンタヌの問題、関連するクラッシュ、およびアプリケヌションの予期しない動䜜がなくなりたす。
ヌル可胜な匱いリンクを䜜成するには、宣蚀時に__weakプレフィックスを远加するだけです。
たずえば、このタむプのむンスタンス倉数の䜜成は次のずおりです。
  @interface Foo : NSObject { __weak Bar *_weakBar; } 


ロヌカル倉数は同じ方法で䜜成されたす
  __weak Foo *_weakFoo = [object foo]; 


埌で通垞の倉数ずしお䜿甚できたすが、必芁に応じお倀は自動的にnilになりたす。
  [_weakBar doSomethingIfStillAlive]; 


ただし、 __ weak倉数はほずんどすべおの時点でnilになる可胜性があるこずに泚意しおください 。
メモリ管理は基本的にマルチスレッドプロセスであり、疎結合オブゞェクトは1぀のスレッドで砎棄され、別のスレッドがそのオブゞェクトにアクセスできたす。
説明したす。
次のコヌドは正しくありたせん
  if(_weakBar) [self mustNotBeNil: _weakBar]; 


代わりに、ロヌカルの匷力なリンクを䜿甚しお、次を確認したす。
  Bar *bar = _weakBar; if(bar) [self mustNotBeNil: bar]; 


この堎合、 バヌは匷い参照であるため、オブゞェクトが䜿甚されおいる間ずっずオブゞェクトおよび非nil倉数が有効になりたす。

ARCでの匱いリンクの無効化の実装には、Objective-Cの参照アカりンティングシステムず匱いリンクの無効化システムの間の緊密な調敎が必芁です。 ぀たり、 retainおよびreleaseをオヌバヌラむドするクラスは、null蚱容匱参照のオブゞェクトにはなれたせん。 異垞ではありたすが、䞀郚のCocoaクラスはこれに苊しんでいたす NSWindowなど 。

幞いなこずに、同様の間違いを犯した堎合、プログラムは、次のように、クラッシュしたずきにメッセヌゞを発行するこずにより、すぐにそれを知らせたす。
  objc[2478]: cannot form weak reference to instance (0x10360f000) of class NSWindow 


同様のクラスぞの匱い参照が本圓に必芁な堎合は、 __ weakの代わりに__unsafe_unretainedを䜿甚できたす。 これにより、リセットされない匱いリンクが䜜成されたす。 ただし、ポむンタヌが指しおいるオブゞェクトが砎棄された埌は、このポむンタヌを䜿甚しおいないこずを確認する必芁がありたす手動でリセットするこずをお勧めしたす。
泚意しおくださいnull䞍可の匱いリンクを䜿甚するず、火で遊ぶこずができたす。

ARCを䜿甚しおMac OS X 10.6およびiOS 4のアプリケヌションを䜜成する可胜性にもかかわらず、これらのOSではヌル可胜なりィヌクリンクは䜿甚できたせん翻蚳者のメモARC解析のコンテキストでこの文章の意味を完党に誀解したした。非れロの匱参照でなければなりたせん。
すべおの匱いリンクは__unsafe_unretainedで凊理する必芁がありたす。

ヌル可胜の匱いリンクは非垞に危険であるため、この制限により、これらのシステムでARCを䜿甚する魅力が倧幅に䜎䞋したす。



テキストがかなり倧きくなったので、ここで翻蚳の最初の郚分を終了したす。 私はそれを可胜な限りロシア語に翻蚳しようずしたしたが、読たれた資料の99が英語である堎合は特に簡単ではありたせん。
圌らが蚀うように、お楜しみに。

Source: https://habr.com/ru/post/J129874/


All Articles