Синглтон — это шаблон проектирования, который обычно используется для разработки класса, так что в приложении должен существовать только один экземпляр этого класса.

В Objective-C наиболее распространенной реализацией такого класса является использование dispatch_once, когда код внутри блока будет выполняться только один раз.

+ (instancetype)sharedInstance {
    static MySingletonClass *_sharedInstance = nil;
    static dispatch_once_t oncePredicate;
    dispatch_once(&oncePredicate, ^{
        _sharedInstance = [[self alloc] initSingletonObject];
    });
    return _sharedInstance;
}

Как задокументировано:

При одновременном вызове из нескольких потоков эта функция синхронно ожидает завершения блока.

При этом мы можем быть уверены, что сможем получить доступ к нашему экземпляру синглтона из этого метода sharedInstance, как и ожидалось, даже в многопоточной ситуации.

Когда каждый член команды, участвующий в соответствующем проекте, знает о предоставленном нами методе sharedInstance, проблем не возникнет. Но иногда мы не могли ожидать, что все прочитают методы инициализации класса и найдут правильный, прежде чем использовать его.

И в Objective-C довольно часто мы создаем наш класс, чтобы наследовать NSObject прямо/косвенно, что делает наш класс init методом NSObject.

Это означает, что даже если бы мы уже предоставили этот метод sharedInstance, никто не мог бы помешать другим людям создать еще один новый экземпляр, создав его напрямую, как показано ниже.

MySingletonClass *firstInstance = [[MySingletonClass alloc] init];
MySingletonClass *secondInstance = [MySingletonClass new];

Неиспользование ожидаемого экземпляра синглтона может легко привести к неожиданной ситуации, которая вызовет ошибку.

Чтобы избежать этой ситуации, мы могли бы предпринять некоторые превентивные действия, пометив NSObject.init и связанные методы как недоступные.

Это можно сделать с помощью NS_UNAVAILABLE, что является короткой формой UNAVAILABLE_ATTRIBUTE, что является короткой формой __attribute__((unavailable)). Мы могли бы поместить приведенный ниже пример кода в файл заголовка класса.

- (instancetype)init NS_UNAVAILABLE;
+ (instancetype)new __attribute__((unavailable("Use +[MySingletonClass sharedInstance] instead")));

Пометив эти методы как недоступные, мы можем помешать другим людям создать неожиданный новый экземпляр. Ошибки появятся во время компиляции.

Таким образом, мы могли бы заставить распределение экземпляров нашего одноэлементного класса вести себя так, как предполагалось.

Мы не только предоставляем метод для получения ОДНОГО единственного экземпляра, но и предотвращаем создание другими людьми более ОДНОГО экземпляра по ошибке.

Не забыл упомянуть, что иногда наш класс может наследовать другой класс, поддерживающий copy или mutableCopy, мы также можем применить аналогичную стратегию с этим методом.