{"id":178,"date":"2009-06-16T19:51:35","date_gmt":"2009-06-17T03:51:35","guid":{"rendered":"http:\/\/eschatologist.net\/blog\/?p=178"},"modified":"2009-06-17T14:34:27","modified_gmt":"2009-06-17T22:34:27","slug":"singletons-in-objective-c","status":"publish","type":"post","link":"https:\/\/eschatologist.net\/blog\/?p=178","title":{"rendered":"Singletons in Cocoa\/Objective-C"},"content":{"rendered":"<p>I&#8217;ll preface this post with the standard advice:  *Don&#8217;t create singletons if you don&#8217;t absolutely have to.*  In general, if you&#8217;re creating a global &#8220;manager&#8221; object of some sort, you&#8217;re doing something wrong.  <\/p>\n<p>That said, there&#8217;s still occasionally a reason to have such a global singleton, such as a &#8220;default something.&#8221;  The sample code in the <a href=\"http:\/\/developer.apple.com\/documentation\/Cocoa\/Conceptual\/CocoaFundamentals\/CocoaObjects\/CocoaObjects.html#\/\/apple_ref\/doc\/uid\/TP40002974-CH4-SW32\">Cocoa Fundamentals Guide<\/a> goes to a lot more trouble than it needs to in order to *ensure* that a class is a singleton.<\/p>\n<p>This is almost **never** what you want.<\/p>\n<p>First off, you probably want your class to be testable in a variety of configurations.  In your unit tests, instead of getting your shared singleton instance in your `-setUp` method and &#8220;resetting&#8221; its state in `-tearDown`, you&#8217;d be better off just instantiating a *new* instance in `-setUp` and *releasing* it in `-tearDown`.<\/p>\n<p>Also, the example in the Cocoa Fundamentals Guide does a lot of work that it simply doesn&#8217;t need to.  This is all you *really* need to do to create a singleton in Cocoa:<\/p>\n<p>    @interface SomeManager : NSObject<br \/>\n    + (id)sharedManager;<br \/>\n    @end<\/p>\n<p>    @implementation SomeManager<\/p>\n<p>    + (id)sharedManager {<br \/>\n        static id sharedManager = nil;<\/p>\n<p>        if (sharedManager == nil) {<br \/>\n            sharedManager = [[self alloc] init];<br \/>\n        }<\/p>\n<p>        return sharedManager;<br \/>\n    }<\/p>\n<p>    @end<\/p>\n<p>That&#8217;s it!  The astute reader will notice, of course, that this isn&#8217;t thread-safe.  I got rid of the `@synchronized (self)` because it won&#8217;t do the right thing; depending on what actual class is sent `+sharedManager`, the value of `self` will be different!<\/p>\n<p>For the sake of argument, though, let&#8217;s say that you do want a singleton with which you can interact from multiple threads at once.  One way to do this would be to create your singleton instance in `+initialize` since it will always be run, on a single thread, before any other methods in your class:<\/p>\n<p>    @implementation SomeManager<\/p>\n<p>    static id sharedManager = nil;<\/p>\n<p>    + (void)initialize {<br \/>\n        if (self == [SomeManager class]) {<br \/>\n            sharedManager = [[self alloc] init];<br \/>\n        }<br \/>\n    }<\/p>\n<p>    + (id)sharedManager {<br \/>\n        return sharedManager;<br \/>\n    }<\/p>\n<p>    @end<\/p>\n<p>By doing this, you avoid the performance bottleneck of `@synchronized` taking a recursive lock every time `+sharedManager` is invoked.<\/p>\n<p>If you want to get fancier, and it&#8217;s OK to temporarily have more than one instance of your singleton created, you could even use `objc_atomicCompareAndSwapGlobalBarrier` to assign the value to return from `+sharedManager`, though this is probably also more work than it&#8217;s worth; after all, `+initialize` will only be invoked once for your class.  (Though it can be re-invoked as a side-effect of initializing subclasses, hence the `if (self == [SomeManager class]) { }` idiom.)<\/p>\n<p>In all of the above cases, you&#8217;ve done a whole lot less work than the example in the Cocoa Fundamentals Guide, and your code is a lot more likely to be correct as a result.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I&#8217;ll preface this post with the standard advice: *Don&#8217;t create singletons if you don&#8217;t absolutely have to.* In general, if you&#8217;re creating a global &#8220;manager&#8221; object of some sort, you&#8217;re doing something wrong. That said, there&#8217;s still occasionally a reason to have such a global singleton, such as a &#8220;default something.&#8221; The sample code in&hellip;<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[3],"tags":[9,127,18,7],"class_list":["post-178","post","type-post","status-publish","format-standard","hentry","category-technology","tag-cocoa","tag-design-patterns","tag-objective-c","tag-unit-testing"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p74loH-2S","_links":{"self":[{"href":"https:\/\/eschatologist.net\/blog\/index.php?rest_route=\/wp\/v2\/posts\/178","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/eschatologist.net\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/eschatologist.net\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/eschatologist.net\/blog\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/eschatologist.net\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=178"}],"version-history":[{"count":10,"href":"https:\/\/eschatologist.net\/blog\/index.php?rest_route=\/wp\/v2\/posts\/178\/revisions"}],"predecessor-version":[{"id":188,"href":"https:\/\/eschatologist.net\/blog\/index.php?rest_route=\/wp\/v2\/posts\/178\/revisions\/188"}],"wp:attachment":[{"href":"https:\/\/eschatologist.net\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=178"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/eschatologist.net\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=178"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/eschatologist.net\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=178"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}