Перерасчет dispatch_once внутри + ?

Если я создаю одноэлемент внутри +[NSObject initialize] , мне нужно поместить мой код внутри блока dispatch_once так?

 static NSObject * Bar; @implementation Foo + (void)initialize { if (self == [Foo class]) { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ Bar = [NSObject new]; }); } } @end 

РЕДАКТИРОВАТЬ

Я беспокоюсь об этом, потому что хочу, чтобы все потоки увидели, что я установил Bar после +[Foo initialize] . В документации указано, что +[NSObject initialize] является потокобезопасной, но означает ли это, что она безопасна для памяти?

3 Solutions collect form web for “Перерасчет dispatch_once внутри + ?”

Ответ на ваш прямой вопрос заключается в том, что вам не нужен dispatch_once , но вам нужна проверка класса, которая у вас есть, потому что +initialize будет вызываться один раз для «не реализующего подкласса» . Он будет вызываться только один раз для конкретного класса, который вам нужен ( Foo ), поэтому dispatch_once является посторонним. Re: безопасность потоков, метод +initialize будет завершен до отправки других методов классу (или его экземплярам).

Однако вы не описываете желаемый шаблон доступа, поэтому в зависимости от того, что вы хотите, вы можете сделать обратное – если вы ожидаете, что подклассы также будут иметь доступ к Bar , тогда это будет хрупким; если подкласс инициализируется до самого Foo , тогда проверка класса предотвратит создание Bar . Если вы намереваетесь на такое поведение, используйте dispatch_once но удалите проверку класса – что обычно позволяет создавать Bar в первый раз, когда Foo или любой из его подклассов инициализируются. (Предостережение: если подкласс также переопределяет +initialize , конечно .)

Билл Бумгарнер говорит, что dispatch_once – это рекомендуемая практика Apple .

Что касается потока и безопасности памяти +initialize , благодаря этому твиту , я нашел соответствующие источники времени выполнения для проверки. objc-initialize.mm говорит:

  * Only one thread is allowed to actually initialize a class and send * +initialize. Enforced by allowing only one thread to set CLS_INITIALIZING. 

Классы могут быть инициализированы на разных потоках, и objc-initialize.mm имеет стратегию, чтобы избежать их блокировки:

 * +initialize deadlock case when a class is marked initializing while * its superclass is initialized. Solved by completely initializing * superclasses before beginning to initialize a class. * * OmniWeb class hierarchy: * OBObject * | ` OBPostLoader * OFObject * / \ * OWAddressEntry OWController * | * OWConsoleController * * Thread 1 (evil testing thread): * initialize OWAddressEntry * super init OFObject * super init OBObject * [OBObject initialize] runs OBPostLoader, which inits lots of classes... * initialize OWConsoleController * super init OWController - wait for Thread 2 to finish OWController init * * Thread 2 (normal OmniWeb thread): * initialize OWController * super init OFObject - wait for Thread 1 to finish OFObject init * * deadlock! * * Solution: fully initialize super classes before beginning to initialize * a subclass. Then the initializing+initialized part of the class hierarchy * will be a contiguous subtree starting at the root, so other threads * can't jump into the middle between two initializing classes, and we won't * get stuck while a superclass waits for its subclass which waits for the * superclass. 

Кроме того, переменные состояния инициализации класса охраняются monitor_t , который фактически определяется как :

 typedef struct { pthread_mutex_t mutex; pthread_cond_t cond; } monitor_t; 

Поскольку это p_thread_mutex , а вызовы p_thread реализуют барьеры памяти , одинаково безопасно использовать:

 static NSObject * Bar; @implementation Foo + (void)initialize { if (self == [Foo class]) { Bar = [NSObject new]; } } @end 

а также

 static NSObject * Bar; @implementation Foo + (void)initialize { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ Bar = [NSObject new]; }); } @end 

В документах упоминается, что метод initialize вызывается только один раз для каждого класса поточно-безопасным способом. Поэтому dispatch_once не требуется.

Время выполнения отправляет инициализацию каждому классу в программе ровно один раз перед классом или любым наследуемым от него классом, отправляется его первое сообщение из программы. (Таким образом, метод никогда не может быть вызван, если класс не используется.) Время выполнения отправляет сообщение инициализации классам в потокобезопасном режиме. Суперклассы получают это сообщение перед их подклассами.

РЕДАКТИРОВАТЬ

Как отмечает @Vincent Gable в комментариях, метод initialize может вызываться более одного раза, если подкласс Foo не реализует сам метод initialize . Однако такие вызовы не будут проблемой, потому что есть проверка self == [Foo class] .

  • Если dispatch_sync не использует другой поток, может ли он быть быстрее?
  • Что произойдет, если у меня есть вложенные вызовы dispatch_async?
  • Последовательность выполнения пользовательской параллельной очереди iOS GCD
  • Какое поведение гарантируется в Grand Central Dispatch в Objective-C?
  • Сделать все конечные точки ожидания одной точной конечной точкой
  • Сколько блоков работает в очереди?
  • Реализация параллельной модели чтения с исключительной записью с GCD
  • Любой способ сделать dispatch_queue_t работать в одном потоке?
  • UITableView insertRowsAtIndexPaths: WithRowAnimation без зависания интерфейса
  • stringByEvaluatingJavaScriptFromString: сделать мой пользовательский интерфейс невосприимчивым
  • Block_release освобождение объектов пользовательского интерфейса в фоновом потоке
  • Interesting Posts

    Создать быстрое расширение массива для типизированного массива

    Флаги компоновщика для iOS с Xcode

    Не удалось найти цель с именем `ProjectName`

    iphone: Как показать другое изображение для каждой точки на MapKit?

    Swift SpriteKit – Постепенное увеличение вращения

    iOS 9: Распознаватель жестов был настроен в раскадровке / xib для добавления к нескольким представлениям (не работает)

    Образец CoreText, получение штрихов, косвенные координаты

    NSFetchedResultsController – вызов обратного вызова для отношений

    Как управлять усилением / уровнем входа микрофона на iPhone?

    Как установить цвет текста заголовка UIButton?

    Странное поведение акселерометра Core Motion, реализованное в фоновом режиме

    No Swipe Back при скрытии панели навигации в UINavigationController

    iPad SplitViewController – с помощью раскадровки iPhone ViewController

    Есть ли способ установить содержимое контента UITableView через Storyboard?

    Установить файлы cookie с помощью NSURLSession

    PhoneC: Разработка iOS проста с помощью XCode, Swift3, UITableView, cocatouch, давайте создадим приложения для iPhone, iPad и Macbook.