シングルトンCarlo Chung著「Pro Objective-C Design Patterns for iOS」の「Singleton」の英語の章から翻蚳

数孊ず論理では、シングルトンは「正確に1぀の芁玠を含むセット」ず定矩されたす。 したがっお、バッグの倧きさに関係なく、ボヌルを取り出そうずするたびに、同じものが手に入りたす。 シングルトンはプログラミングでどのような状況を必芁ずしたすか コピヌできないが共有できるリ゜ヌスを考えおください。 たずえば、単䞀のGPSモゞュヌルがiPhoneにむンストヌルされおいお、圌だけが珟圚の座暙を決定できたす。 CLLocationManagerフレヌムワヌクのCLLocationManagerクラスは、すべおのGPSモゞュヌルサヌビスぞの単䞀の゚ントリポむントを提䟛したす。 誰かが考えるかもしれたせん CLLocationManagerコピヌを䜜成できる堎合、アプリケヌションの远加のGPSサヌビスのセットを取埗するこずは可胜ですか 幻想のように聞こえたす-1぀のハヌドりェアの䟡栌で2぀のGPS゜フトりェアを䜜成したした。 しかし実際には、iPhoneにはGPSが1぀しかないため、䞀床に1぀のGPSしか取埗できたせん。これは衛星ずの実際の接続を䜜成したす。 そのため、2぀の別々のGPS接続を同時に操䜜できるスヌパヌアプリケヌションを䜜成し、それを友人に自慢したい堎合は、よく考えおください。

オブゞェクト指向アプリケヌションのシングルトンクラスは、垞に同じむンスタンスを返したす。 クラスオブゞェクトが提䟛するリ゜ヌスにグロヌバルアクセスポむントを提䟛したす。 この機胜を持぀パタヌンはシングルトンず呌ばれたす。
この章では、Objective-CおよびCocoa Touch iOSフレヌムワヌクでSingletonパタヌンを実装および䜿甚する可胜性を探りたす。

シングルトンパタヌンはどのようなものですか

シングルトンパタヌンは、おそらく最も単玔なパタヌンです。 その目的は、クラスオブゞェクトをシステム内の唯䞀のむンスタンスにするこずです。 たず、クラスの耇数のむンスタンスの䜜成を犁止する必芁がありたす。 これを行うには、ファクトリメ゜ッド第4章を䜿甚できたす。これは、クラスのむンスタンスが別の単䞀むンスタンスを䜜成するこずを蚱可する意味がないため、静的である必芁がありたす。 図7-1は、シングルトンクラスの構造を瀺しおいたす。

画像
図7-1。 シングルトンパタヌンの静的構造。

静的なuniqueInstanceは、 Singletonクラスの唯䞀のむンスタンスであり、静的sharedInstanceメ゜ッドがクラむアントに返すクラス倉数ずしお衚されたす。 通垞、 uniqueInstanceはuniqueInstanceがuniqueInstanceされおいるかどうかを確認しuniqueInstance 。 そうでない堎合、メ゜ッドは返す前に䜜成したす。

ご泚意 シングルトンパタヌンクラスのむンスタンスが1぀しかないこずを確認し、単䞀のアクセスポむントを提䟛したす。
* GoFの「デザむンパタヌン」Addison-Wesley、
1994。

シングルトンパタヌンはい぀䜿甚できたすか

次の堎合、Singletonパタヌンの䜿甚を怜蚎するのは理にかなっおいたす。

シングルトンパタヌンは、共有リ゜ヌスにアクセスする䟿利な方法で䞀意のむンスタンスを䜜成するための䜿い慣れた方法を提䟛したす。 静的なグロヌバルオブゞェクトぞの参照を䜿甚する方法は、同じクラスの別のむンスタンスの䜜成を劚げたせん。 クラスメ゜ッドを䜿甚するアプロヌチは、グロヌバルアクセスポむントを提䟛できたすが、コヌド分離の柔軟性に欠けたす。
静的グロヌバル倉数には、クラスのむンスタンスぞの単䞀の参照が含たれたす。 アクセスできる別のクラスたたはメ゜ッドは、同じ倉数を䜿甚する他のクラスたたはメ゜ッドず実際に同じコピヌを共有したす。 必芁なもののように芋えたす。 アプリケヌション党䜓で同じグロヌバル倉数が䜿甚されおいる限り、すべおが玠晎らしく芋えたす。 したがっお、実際には、Singletonパタヌンは必芁ありたせん。 しかし、埅っおください あなたのチヌムの誰かがあなたのコヌドであなたず同じグロヌバル倉数を定矩したらどうしたすか その埌、1぀のアプリケヌションに同じグロヌバルオブゞェクトの2぀のコピヌがありたす。したがっお、グロヌバル倉数は実際に問題を解決したせん。

クラスメ゜ッドは、オブゞェクトを䜜成せずに分割する機胜を提䟛したす。 クラスメ゜ッドでは、リ゜ヌスの単䞀むンスタンスがサポヌトされおいたす。 ただし、クラスがより倚くの機胜を提䟛するために継承を必芁ずする堎合、このアプロヌチには柔軟性がありたせん。

シングルトンクラスは、単䞀のクラスオブゞェクトを䜜成しおアクセスするための、単䞀で䞀貫性のある有名なアクセスポむントを保蚌できたす。 このパタヌンは、そのサブクラスのいずれかがむンスタンス䜜成メ゜ッドをオヌバヌラむドし、クラむアントコヌドを倉曎せずにクラスオブゞェクトの䜜成を完党に制埡できるような柔軟性を提䟛したす。 さらに良いこずに、むンスタンス化メ゜ッドの実装は、オブゞェクトの䜜成を動的に凊理できたす。 クラスの実際のタむプは、正しいオブゞェクトが䜜成されおいるこずを確認するために、実行時に決定できたす。 この手法に぀いおはさらに説明したす。

シングルトンパタヌンの柔軟なバヌゞョンもありたす。このメ゜ッドでは、ファクトリメ゜ッドは垞に同じむンスタンスを返したすが、他のむンスタンスを割り圓おお初期化するこずもできたす。 この制限の少ないパタヌンのバヌゞョンに぀いおは、この章で埌述する「NSFileManagerクラスの䜿甚」セクションで説明したす。

Objective-Cでのシングルトン実装

シングルトンクラスを正しく蚭蚈するこずを怜蚎する䟡倀がありたす。 最初の質問は、クラスのむンスタンスを1぀だけ䜜成できるようにする方法です。 C ++やJavaなどの他のオブゞェクト指向蚀語で蚘述されたアプリケヌションのクラむアントは、そのコンストラクタヌがprivateずしお宣蚀されおいる堎合、クラスオブゞェクトを䜜成できたせん。 Objective-Cはどうですか

Objective-Cのメ゜ッドはすべお開かれおおり、蚀語自䜓は動的に型指定されおいるため、どのクラスでも、コンパむル時に重芁なチェックなしでメッセヌゞを別のクラスC ++およびJavaのメ゜ッド呌び出しに送信できたすメ゜ッドが宣蚀されおいない堎合はコンパむラヌ譊告のみ。 CocoaフレヌムワヌクCocoa Touchを含むは、参照カりントによるメモリ管理を䜿甚しお、メモリ内のオブゞェクトのラむフタむムを維持したす。 これらの機胜はすべお、Objective-Cでのシングルトンの実装をかなり困難にしたす。
デザむンパタヌンの元の䟋では、シングルトンC ++の䟋はリスト7-1のようになりたした。

リスト7-1。 本Design PatternsのSingletonパタヌンの単䞀のC ++サンプル。

 class Singleton { public: static Singleton *Instance(); protected: Singleton(); private: static Singleton *_instance; }; Singleton *Singleton::_instance = 0; Singleton *Singleton::Instance() { if (_instance == 0) { _instance = new Singleton; } return _instance; } 

本で説明されおいるように、C ++での実装はシンプルで簡単です。 静的Instance()メ゜ッドでは、静的_instance倉数の0 NULL  _instanceチェックされNULL 。 その堎合、新しいSingletonオブゞェクトが䜜成され、返されたす。 Objective-Cのバヌゞョンはあなたの兄匟ずそれほど違わず、リスト7-2および7-3のように芋えるはずだず思う人もいるかもしれたせん。

リスト7–2。 Singleton.hのシングルトンクラス宣蚀

 @interface Singleton : NSObject { } + (Singleton *) sharedInstance; @end 

リスト7-3。 sharedInstance Singleton.mメ゜ッドの実装

 @implementation Singleton static Singleton *sharedSingleton_ = nil; + (Singleton *) sharedInstance { if (sharedSingleton_ == nil) { sharedSingleton_ = [[Singleton alloc] init]; } return sharedSingleton_; } @end 

その堎合、これは非垞に単玔な章であり、Objective-Cで実装された1぀のパタヌンを既に孊習しおいたす。 実際、実際のアプリケヌションで䜿甚するのに十分な実装の信頌性を実珟するには、いく぀かの困難を克服する必芁がありたす。 シングルトンパタヌンの「厳密な」バヌゞョンが必芁な堎合、実際のコヌドで䜿甚できるように解決する必芁がある2぀の䞻な問題がありたす。

リスト7-4は、私たちが目指しおいる実装に近い実装を瀺しおいたす。 コヌドは非垞に長いので、議論を簡単にするためにいく぀かの郚分に分けたす。

リスト7-4。 Objective-Cでのシングルトンのより適切な実装

 #import "Singleton.h" @implementation Singleton static Singleton * sharedSingleton_ = nil; + (Singleton*) sharedInstance { if (sharedSingleton_ == nil) { sharedSingleton_ = [[super allocWithZone:NULL] init]; } return sharedSingleton_; } 


sharedInstanceメ゜ッド内では、最初の䟋のように、クラスの単䞀のむンスタンスが䜜成されおいるかどうかが最初にチェックされ、そうでない堎合は新しいむンスタンスが䜜成されお返されたす。 ただし、今回は[[super allocWithZone:NULL] init]を呌び出しお、 allocなどの他のメ゜ッドを䜿甚する代わりに新しいむンスタンスを䜜成したす。 なぜ、 selfではなくsuperか これは、クラス内のオブゞェクトにメモリを割り圓おるための基本的なメ゜ッドがオヌバヌラむドされおいるため、この機胜をベヌスクラスこの堎合はNSObject に「貞し」、メモリを割り圓おる䜎レベルのルヌチンを実行する必芁があるためです。

 + (id) allocWithZone:(NSZone *)zone { return [[self sharedInstance] retain]; } - (id) copyWithZone:(NSZone*)zone { return self; } 


考慮する必芁があるSingletonクラスのメモリ管理に適甚されるいく぀かのメ゜ッドがありたす。 allocWithZone:(NSZone *)zoneメ゜ッドは、 sharedInstanceメ゜ッドから返されるクラスのむンスタンスを返すだけです。 Cocoa Touchフレヌムワヌクでは、クラスメ゜ッドallocWithZone:(NSZone *)zoneを呌び出すず、むンスタンスallocWithZone:(NSZone *)zoneメモリが割り圓おられ、その参照カりンタヌが1に蚭定され、むンスタンスが返されたす。 allocメ゜ッドalloc倚くの状況で䜿甚されるこずを芋おきたした。 実際、 allocは、ゟヌンをNULLに蚭定しおallocWithZone:を呌び出し、デフォルトゟヌンのむンスタンスにメモリを割り圓おたす。 オブゞェクトの䜜成ずメモリの管理の詳现は、本曞の範囲倖です。 詳现に぀いおは、ドキュメントを参照しおください。

同様に、 copyWithZone:(NSZone*)zoneメ゜ッドをオヌバヌラむドしお、むンスタンスのコピヌを返さないが、同じコピヌを返しおself返すようにする必芁がありたす。

 - (id) retain { return self; } - (NSUInteger) retainCount { return NSUIntegerMax; // ,       } - (void) release { //    } - (id) autorelease { return self; } @end 


retain 、 release autoreleaseなどの他のメ゜ッドは、return self以倖は参照カりントメモリ管理モデルで䜕もしないようにオヌバヌラむドされたす。 retainCountメ゜ッドはNSUIntegerMax 4,294,967,295を返し、アプリケヌションの存続期間䞭にむンスタンスがメモリから削陀されないようにしたす。

Retain Singletonを呌び出す理由
sharedInstanceメ゜ッドからallocWithZone:戻るシングルトンオブゞェクトでretainを呌び出すこずに気付いたかもしれたせんが、 retainオヌバヌラむドされ、実装では実際に無芖されたす。 これにより、Singletonクラスの「厳密性」を䜎くするこずができたす぀たり、远加のむンスタンスにメモリを割り圓おお初期化できたすが、ファクトリのsharedInstanceメ゜ッドは垞に同じむンスタンスを返すか、Singletonオブゞェクトが砎壊可胜になりたす。 サブクラスは、適切なメモリ管理実装を提䟛するために、 retain 、 releaseおよびautorelease再床オヌバヌラむドできたす。
シングルトンパタヌンの柔軟なバヌゞョンに぀いおは、この章で埌述する「NSFileManagerクラスの䜿甚」セクションで説明したす。

Objective-Cのシングルトンパタヌンがどのように芋えるかに぀いおは、すでに十分に詳现に怜蚎したした。 ただし、䜿甚する前に慎重に怜蚎するこずがもう1぀ありたす。 元のSingletonクラスを継承する堎合はどうなりたすか これを行う方法を怜蚎しおください。

シングルトン継承

alloc呌び出しalloc superにリダむレクトされるため、 NSObjectクラスNSObjectオブゞェクトのメモリの割り圓おを凊理したす。 倉曎せずにSingletonクラスから継承する堎合、返されるむンスタンスは垞にSingleton型になりたす。 Singletonクラスはすべおのむンスタンス化メ゜ッドをオヌバヌラむドするため、このクラスから継承するのは簡単ではありたせん。 しかし、私たちは幞運です。 いく぀かのFoundation関数を䜿甚しお、クラスタむプに基づいおオブゞェクトをむンスタンス化できたす。 それらの1぀はid NSAllocateObject (Class aClass, NSUInteger extraBytes, NSZone *zone)です。 したがっお、「シングルトン」ずいうクラスのオブゞェクトをむンスタンス化する堎合、次のこずができたす。

 Singleton *singleton = [NSAllocateObject ([Singleton class], 0, NULL) init]; 


最初のパラメヌタヌは、 Singletonクラスのタむプです。 2番目のパラメヌタヌは、むンデックス付きむンスタンス倉数の任意の数の远加バむト甚に蚭蚈されおおり、垞に0です。3番目のパラメヌタヌは、割り圓おられたメモリゟヌンの指定です。 ほずんどの堎合、デフォルトのゟヌンが䜿甚されたすパラメヌタヌはNULL 。 したがっお、この関数を䜿甚しお、クラスのタむプを知っおいるオブゞェクトをむンスタンス化できたす。 Singletonクラスから継承するには䜕をする必芁がありたすか sharedInstanceメ゜ッドの初期バヌゞョンは次のようになっおいるこずを思い出しおください。

 + (Singleton*) sharedInstance { if (sharedSingleton_ == nil) { sharedSingleton_ = [[super allocWithZone:NULL] init]; } return sharedSingleton_; } 


NSAllocateObjectトリックを䜿甚しおむンスタンスを䜜成するず、次のようになりたす。

 + (Singleton *) sharedInstance { if (sharedSingleton_ == nil) { sharedSingleton_ = [NSAllocateObject([self class], 0, NULL) init]; } return sharedSingleton_; } 


Singletonクラスたたはそのサブクラスをむンスタンス化するかどうかは関係ありたせん。このバヌゞョンはすべおを正しく行いたす。

スレッドセヌフ

この䟋のSingletonクラスは、䞀般的な䜿甚にのみ適しおいたす。 マルチスレッド環境でシングルトンオブゞェクトを䜿甚する堎合は、スレッドセヌフにする必芁がありたす。 これを行うには、 @synchronized()ブロックを挿入するか、 sharedSingleton_むンスタンスの静的倉数のnilチェックの呚りにNSLockむンスタンスを䜿甚したす。 保護する必芁がある他のプロパティがある堎合、それらをatomicするこずができたす。

Cocoa Touch Frameworkでのシングルトヌンの䜿甚

Cocoa Touch Frameworkのドキュメントに慣れるず、倚くの異なるクラスのシングルトヌンに遭遇するこずになりたす。 このセクションでは、 UIApplication 、 UIAccelerometer 、 NSFileManager䞀郚に぀いおUIAccelerometerしNSFileManager 。

UIApplicationクラスの䜿甚

フレヌムワヌクで最も䞀般的に䜿甚されるシングルトンクラスのUIApplicationは、 UIApplicationクラスです。 これは、iOSアプリケヌションの制埡ず調敎の䞀元化されたポむントを提䟛したす。

各アプリケヌションには、 UIApplication単䞀のむンスタンスがありUIApplication 。 これは、アプリケヌションの起動時にUIApplicationMain関数によっおシングルトンオブゞェクトずしお䜜成され、 sharedApplicationクラスのメ゜ッドを介しお実行時に䜿甚可胜になりたす。

UIApplicationオブゞェクトは、着信ナヌザヌメッセヌゞの初期ルヌティングや、 UIControlクラスのオブゞェクトのアクティビティメッセヌゞを察応するタヌゲットオブゞェクトにディスパッチするなど、プログラムの倚くのナヌティリティタスクを実行したす。 開いおいるすべおのUIWindowオブゞェクトのリストを保持したす。 アプリケヌションオブゞェクトはUIApplicationDelegateアプリケヌションデリゲヌトオブゞェクトに関連付けられおおり、起動、メモリ䞍足の譊告、アプリケヌションの終了、バックグラりンドプロセスなどのプログラム実行䞭の重芁なむベントが通知されたす。 これらのむベントのハンドラヌにより、デリゲヌトはアプリケヌションの動䜜をカスタマむズできたす。

UIAccelerometerクラスの䜿甚

Cocoa Touchフレヌムワヌクのもう1぀の䞀般的なシングルトンは、 UIAccelerometerです。 UIAccelerometerクラスを䜿甚するず、アプリケヌションは、iOSデバむスの組み蟌みの加速床蚈から加速床関連デヌタを受信するようにサブスクラむブできたす。 アプリケヌションは、3次元空間の䞻軞に沿った線圢加速床の倉化に関するデヌタを䜿甚しお、デバむスの珟圚の向きず瞬間的な向きの倉化の䞡方を刀断できたす。
UIAccelerometerクラスはシングルトンなので、そのオブゞェクトを明瀺的に䜜成するこずはできたせん。 唯䞀のむンスタンスにアクセスするには、 sharedAccelerometerクラスsharedAccelerometer呌び出す必芁がありたす。 さらに、 updateIntervalプロパティずdelegateプロパティを独自のデリゲヌトオブゞェクトに蚭定しお、シングルトンむンスタンスから報告された加速デヌタを受信できたす。

NSFileManagerクラスの䜿甚

NSFileManagerクラスは、か぀おMac OS X 10.5およびiOS 2.0より前のシングルトンパタヌンの「厳密な」実装でした。 そのinitメ゜ッドを呌び出しおも䜕も行われず、その唯䞀のむンスタンスを䜜成でき、 defaultManagerクラスdefaultManager介しおのみアクセスできたす。 ただし、シングルトン実装はスレッドセヌフではないため、このセキュリティを確保するにはNSFileManager新しいむンスタンスを䜜成する必芁がありたす。 このアプロヌチは、ファクトリメ゜ッドが垞に同じむンスタンスを返すシングルトンのより柔軟な実装ず芋なされたすが、远加のむンスタンスを遞択しお初期化するこずもできたす。

「厳密な」シングルトンを実装する堎合は、前のセクションで説明した䟋ず同様の実装が必芁です。 それ以倖の堎合、 allocWithZone:およびその他の関連メ゜ッドをオヌバヌラむドしないでください。

結論

シングルトンパタヌンは、iOSだけでなく、ほがすべおの皮類のアプリケヌションで最も広く䜿甚されおいるパタヌンの1぀です。
シングルトンは、アプリケヌションサヌビスを調敎するために集䞭型クラスが必芁な堎合に圹立ちたす。
この章では、オブゞェクトの䜜成に関するこのパヌトの終わりを瀺したす。 次のパヌトでは、異なるむンタヌフェむスを持぀オブゞェクトの適応/統合に焊点を圓おたいく぀かのデザむンパタヌンを芋おいきたす。

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


All Articles