Что эквивалентно синхронизированному в Objective-C? - PullRequest
5 голосов
/ 02 ноября 2010

Что эквивалентно java, синхронизированной в цели c?Я хочу иметь возможность сделать мой одноэлементный метод безопасным, поэтому, когда он вызывается из 2 разных потоков, они пытаются использовать его 1 на 1.

+(MyObject*) getSharedObject
{
     if(!singleton)
     {
          singleton = [[MyObject alloc] init];
     }
     return singleton;
}

Ответы [ 4 ]

10 голосов
/ 02 ноября 2010

Obj-C имеет синхронизированную конструкцию

-(MyObject*) getSharedObject
{
@synchronized(something)
{
     if(!singleton)
     {
          singleton = [[MyObject alloc] init];
     }
     return singleton;
}
}

возвращение из синхронизированного блока делает правильную вещь

9 голосов
/ 02 ноября 2010

Ответ Джошуа верен, но требует, чтобы у вас был объект для синхронизации.Выполнение этого для одиночного прыжка может привести к всевозможным странным условиям гонки, если вы не будете осторожны.Стандартный шаблон для синглтона - инициализировать его в +initialize, используя dispatch_once, что правильно:

static MyObject *singleton = nil;

+ (void)initialize {
  static dispatch_once_t pred;
  dispatch_once(&pred, ^{ singleton = [[MyObject alloc] init]; } );
}

- (MyObject&)getSharedObject
{
  return singleton;
}
8 голосов
/ 02 ноября 2010

Для синхронизации создания синглтона вы должны использовать класс синглтона в качестве объекта для синхронизации.Это мой обычный шаблон:

+(MyObject*) singleton
{
    static MyObject* singleton = nil;
    @synchronized([MyObject class])
    {
         if(singleton == nil)
         {
             singleton = [[MyObject alloc] init];
         }
    }
    return singleton;
}

Обратите внимание:

  • Я сделал это методом класса.На самом деле это не обязательно, он будет работать как метод экземпляра.

  • Обычно в методах класса при обращении к классу вы используете self (или [self class]в экземплярах методов).Однако это было бы неправильно, поскольку подклассы синхронизировались бы с использованием объекта, отличного от класса MyObject.

  • Я поместил возврат за пределы блока @synchronize.Это вполне нормально, чтобы вернуться изнутри блока, но если вы это сделаете, вы получите ложное предупреждение статического анализатора лязга, говорящее, что метод может не возвращать значение.* Edit

    Вышеприведенный шаблон давно устарел.Лучше всего использовать dispatch_once шаблон

    +(MyObject*) singleton
    {
        static dispatch_once_t onceToken;
        static MyObject* singleton = nil;
    
        dispatch_once (&onceToken, ^{
            singleton = [[MyObject alloc] init];
        });
        return singleton;
    }
    
0 голосов
/ 02 ноября 2010

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

if (!singleton)  
   @synchronized(something)  
      if (!singleton)  
         instantiate;

Таким образом вы избегаете ненужной блокировки после создания объекта.

...