4

I'm trying to create a singleton class in Objective-C that will also be consumed in Swift. I'd like the singleton instance to be accessible in Swift as a property.

It appears that Apple does something similar (though not quite a singleton) in NSFileManager.

@property(class, readonly, strong) NSFileManager *defaultManager;

Ref: https://developer.apple.com/documentation/foundation/nsfilemanager/1409234-defaultmanager

Here's my (simplified) attempt so far:

FOOMyManager.h:

@interface FOOMyManager : NSObject

@property(class, readonly, strong) FOOMyManager *defaultManager;

- (instancetype)init NS_UNAVAILABLE;

@end

FOOMyManager.mm

@implementation FOOMyManager

+ (FOOMyManager *)defaultManager {
    static dispatch_once_t s_once = 0;
    static FOOMyManager *s_instance = nil;
    dispatch_once(&s_once, ^{
        s_instance = [[FOOMyManager alloc] initForDefaultManager];
    });

    return s_instance;
}

- (instancetype)initForDefaultManager {
    self = [super init];
    return self;
}

@end

I've seen instances of a similar pattern being used to create singletons using

+ (instancetype)defaultManager;

But I'd explicitly like to try and use properties if possible. Is my attempt the "right" way to do this?

K Mehta
  • 10,323
  • 4
  • 46
  • 76
  • 1
    There are many similar queastions already: https://stackoverflow.com/questions/5381085/how-to-create-singleton-class-in-objective-c, https://stackoverflow.com/questions/46319731/objective-c-singleton-implementation, https://stackoverflow.com/questions/7568935/how-do-i-implement-an-objective-c-singleton-that-is-compatible-with-arc, https://stackoverflow.com/questions/145154/what-should-my-objective-c-singleton-look-like, https://stackoverflow.com/questions/16208041/what-is-the-use-of-singleton-class-in-objective-c. – lazarevzubov Jun 04 '23 at 07:56
  • Also, apart from `init` don't forget to make `new` `NS_UNAVAILABLE`, too. – lazarevzubov Jun 04 '23 at 07:56
  • 2
    @lazarevzubov I did look through those. Unfortunately, none of them use @ property for this. I'd like to know if the pattern I'm using with @ property has any downfalls. – K Mehta Jun 05 '23 at 03:12
  • Does this answer your question? [How do I declare class-level properties in Objective-C?](https://stackoverflow.com/questions/695980/how-do-i-declare-class-level-properties-in-objective-c) Skip the answers before 2016. – Willeke Jun 05 '23 at 08:30
  • 1
    @Willeke I'm afraid not. I know how to create a property, as is the case in my attempt so far. I just don't know if I'm creating the property correctly when implementing the singleton pattern. The fact that I haven't been able to find examples of this and yet Apple seems to be moving in this direction is why I want to double check my approach. – K Mehta Jun 05 '23 at 16:38
  • Apple just changed the interfaces from a getter to a property. `NSFileManager.defaultManager` exists since OS X 10.0. Is the question about the declaration of the property or about the implementation of the singleton? – Willeke Jun 05 '23 at 16:58
  • @KMehta what about this: https://stackoverflow.com/questions/12631705/singleton-property-access-in-objective-c ? does it help? – Andrey Jun 05 '23 at 17:29
  • Or this https://www.galloway.me.uk/tutorials/singleton-classes/ ? – Andrey Jun 05 '23 at 17:30
  • @Willeke the question is about implementing the singleton pattern where the singleton reference is exposed as a class property. – K Mehta Jun 06 '23 at 01:00
  • @Andrey neither of those answer the question. They're both about calling a property on a singleton, which is different from accessing the singleton instance as a class property of an interface. – K Mehta Jun 06 '23 at 01:01

1 Answers1

3

Yes, you've got the right principles.

You don't need the strong, since that's an attribute used for a synthesized setter telling it that it should retain a strong reference to anything passed into the setter. In this case it's not doing anything since class properties are never synthesized automatically, and it's marked as readonly so strong wouldn't have any effect anyways.

Your code looks good. dispatch_once is the preferred way of instantiating a singleton.

As far as any improvements, you can add a message to the unavailable attribute: __attribute__((unavailable("Use FOOMyManager.defaultManager"))). I wouldn't say it's necessary or adds much since it's clear from the header file what to do, but I'm including it here as an option.

John Coates
  • 116
  • 2
  • 5