Objective-C ARC: сильный против удержания и слабый против присвоения

367

Есть два новых атрибута управления памятью для свойств, представленных ARC, strongи weak.

Кроме того copy, что, очевидно, является чем-то совершенно другим, есть ли различия между strongпротив retainи weakпротив assign?

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

Я не знаю никаких различий между strongи retain.

Есть ли какая-то причина, по которой я должен использовать assignи retainв новых проектах, или они устарели?

Якуб Арнольд
источник
12
Есть три новых атрибута управления памятью для свойств, представленных ARC strong, weakи unsafe_unretained.
NJones
5
@NJones Есть два атрибута собственности ( weakа strong) и 4 переменных отборочных прижизненной ( __strong, __weak, __unsafe_unretained, __autoreleasing). Смотрите примечания ARC ниже.
Snowcrash
1
@SnowCrash Была версия Xcode, вероятно, для предварительного просмотра разработчиком, в которой использование assignпри компиляции с ARC было ошибкой. Есть много удаленных ответов об этом. Похоже, что было изменено до финального релиза. unsafe_unretainedявляется предпочтительным атрибутом для многих из нас ранних последователей. Для доказательства того, что unsafe_unretainedэтот атрибут является действительным, обратитесь к разделу «Программирование с помощью Objective-C» компании Apple в разделе «Инкапсуляция данных» в подзаголовке «Использовать небезопасные нераспределенные ссылки для некоторых классов». Что говорит: «Для свойства это означает использование атрибута unsafe_unretained:»
NJones,

Ответы:

230

Из заметок о переходе на ARC (пример в разделе об атрибутах свойств).

// The following declaration is a synonym for: @property(retain) MyClass *myObject;

@property(strong) MyClass *myObject;

Так strong же, как retainв объявлении свойства.

Для проектов ARC я бы использовал strong вместо retain, я использовал бы assignдля примитивных свойств C и weakдля слабых ссылок на объекты Objective-C.

JeremyP
источник
11
На самом деле, в ARC это ошибка компиляции assignдля объекта. Вы должны использовать либо weakили unsafe_unretained(что небезопасно, очевидно), если вы не хотите сохранять собственность.
коббал
5
assignкомпилируется для меня хорошо в проектах ARC с целью развертывания 4.0.
Паскаль
8
@Pascal: слабые ссылки не разрешены в целях развертывания, где ОС не 5.0 или выше. Так что для более старых проектов вы все еще можете использовать assign, но если вы переходите на более новые версии, вам нужно переключиться на более слабую
Mattia
1
Выглядит как Xcode 4 (с ARC) генерирует NSManagedObject подклассы использованием retainvs. strong. Я предполагаю, что это в основном безвредно, но я предполагаю, что это должно быть strongдля последовательности ... или, возможно, это не имеет значения. stackoverflow.com/questions/7796476/…
Джо Д'Андреа
3
@JeremyP Да, ваш ответ точен. Я реагировал на @Mattia. Я указывал, что assignв некоторых случаях все еще действует.
Стивен Оксли
606

Прочитав так много статей, опубликованных в Stackoverflow и демонстрационных приложениях для проверки атрибутов переменных, я решил собрать всю информацию об атрибутах:

  1. atomic // default
  2. неатомической
  3. strong = сохранить // по умолчанию
  4. слабый
  5. сохранить
  6. назначить // по умолчанию
  7. unsafe_unretained
  8. копия
  9. только для чтения
  10. readwrite // по умолчанию

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

Атрибуты переменных свойств или модификаторы в iOS

1. сильный (iOS4 = сохранить)

  • там написано "держи это в куче, пока я не укажу на это"
  • Другими словами, «Я владелец, вы не можете сдать это, пока не нацелились на то же самое, что и удержали»
  • Вы используете сильный, только если вам нужно сохранить объект.
  • По умолчанию все переменные экземпляра и локальные переменные являются сильными указателями.
  • Обычно мы используем сильный для UIViewControllers (родителей элемента пользовательского интерфейса)
  • Сильный используется с ARC, и он в основном помогает вам, не заботясь о сохранении счета объекта. ARC автоматически выпускает его для вас, когда вы закончите. Использование ключевого слова strong означает, что вы являетесь владельцем объекта.

Пример:

@property (strong, nonatomic) ViewController *viewController;

@synthesize viewController;

2. слабый -

  • он говорит: «Держите это, пока кто-то еще сильно на это указывает»
  • то же самое, что присваивать, не сохранять или освобождать
  • «Слабая» ссылка - это ссылка, которую вы не сохраняете.
  • Как правило, мы используем слабый для IBOutlets (Childs UIViewController). Это работает, потому что дочерний объект должен существовать только столько, сколько родительский объект делает.
  • слабая ссылка - это ссылка, которая не защищает указанный объект от сбора сборщиком мусора.
  • Слабым является, по сути, присваиваемое, оставшееся свойство. За исключением случаев, когда объект освобожден, слабый указатель автоматически устанавливается на ноль

Пример :

@property (weak, nonatomic) IBOutlet UIButton *myButton;

@synthesize myButton;

Сильное и слабое объяснение, благодаря BJ Homer :

Представьте, что наш объект - собака, и что собака хочет убежать (быть освобожденной).

Сильные указатели похожи на поводок на собаку. Пока вы привязали поводок к собаке, собака не убежит. Если пять человек прикрепят поводок к одной собаке (пять сильных указателей на один объект), то собака не убежит, пока все пять поводков не отсоединятся.

Слабые указатели, с другой стороны, похожи на маленьких детей, указывающих на собаку и говорящих "Смотри! Собака!" Пока собака все еще на поводке, маленькие дети все еще могут видеть собаку, и они все еще будут указывать на нее. Однако, как только поводки отстегнуты, собака убегает независимо от того, сколько на нее указывают маленькие дети.

Как только последний сильный указатель (привязь) больше не указывает на объект, объект будет освобожден, а все слабые указатели будут обнулены.

Когда мы используем слабые?

Единственный раз, когда вы захотите использовать слабый, - это если вы хотите избежать циклов сохранения (например, родитель сохраняет ребенка, а ребенок сохраняет родителя, поэтому ни один из них не освобождается).

3. сохранить = сильный

  • оно сохраняется, старое значение освобождается и ему присваивается сохранение, указывает, что новое значение должно быть отправлено
  • сохранить при назначении и старое значение отправлено
  • сохранить так же, как сильный.
  • Apple говорит, что если вы напишите сохранить, он будет автоматически конвертироваться / работать как сильный.
  • такие методы, как «alloc», включают в себя неявное «retain»

Пример:

@property (nonatomic, retain) NSString *name;

@synthesize name;

4.assign

  • assign является значением по умолчанию и просто выполняет присвоение переменной
  • assign - это атрибут свойства, который сообщает компилятору, как синтезировать реализацию метода установки свойства
  • Я хотел бы использовать для примитивных свойств Си и слабые для слабых ссылок на объекты Objective-C.

Пример:

@property (nonatomic, assign) NSString *address;

@synthesize address;
swiftBoy
источник
5
2. «Слабая ссылка - это ссылка, которая не защищает указанный объект от сбора сборщиком мусора» - в цели c нет такой вещи, как сборщик мусора;
Bucherland
1
и эта иерархия управляется iOS автоматически. Читайте о концепции MVC. Я имею в виду, что когда ViewContorller представлен, iOS загружает его иерархию представлений на экран (создавая отсутствующие представления). Когда представлен другой ViewController, эта первая иерархия представлений освобождается. Но если у вас есть «сильный» во ViewController, то это представление не может быть освобождено, когда оно за пределами экрана. Что может оказать сильное влияние на память устройства и привести к замедлению работы приложения. (Конечно, у устройства много памяти, и с приложением с 5-10 экранами все будет в порядке, но в огромном приложении у вас будут проблемы)
bucherland
1
Когда мы используем слабые? 1. Для объектов пользовательского интерфейса: 2. делегаты, 3. блоки (следует использовать вместо себя selfSelf, чтобы избежать циклов памяти (как было упомянуто выше)
bucherland
1
В этом замечательном ответе есть одна ошибка - сильная - «ARC автоматически выпускает его для вас, когда вы закончите», это неправильно. ARC автоматически освобождает слабые объекты, когда на них нет указателей. Сильный - это синоним для сохранения, поэтому объект сохраняется, и наша обязанность сделать объект нулевым
Эшвин Г.
1
@RDC, что defaultзначит? Если я использую @property (nonatomic) NSString *stringэто strong? Или assign? Потому что оба по умолчанию.
Юлиан Онофрей
40

неатомический / атомный

  • неатомный намного быстрее, чем атомный
  • всегда используйте nonatomic, если у вас нет особых требований к atomic, что должно быть редко (atomic не гарантирует безопасность потока - блокирует доступ к свойству, только если он одновременно установлен другим потоком)

сильный / слабый / правопреемник

  • использовать сильный для сохранения объектов - хотя ключевое слово retain является синонимом, вместо него лучше использовать strong
  • использовать слабый если вам нужен только указатель на объект без его сохранения - полезно для избежания сохранения циклов (т. е. делегатов) - он автоматически обнулит указатель при освобождении объекта
  • используйте assign для приматов - точно так же, как и слабый, за исключением того, что он не обнуляет объект при освобождении (устанавливается по умолчанию)

(Необязательный)

копия

  • использовать его для создания мелкой копии объекта
  • Рекомендуется всегда задавать неизменяемые свойства для копирования - поскольку изменяемые версии могут передаваться в неизменяемые свойства, копирование гарантирует, что вы всегда будете иметь дело с неизменным объектом
  • если передан неизменный объект, он сохранит его - если передан изменяемый объект, он скопирует его

только для чтения

  • используйте его, чтобы отключить настройку свойства (предотвращает компиляцию кода при нарушении)
  • вы можете изменить то, что доставляет получатель, либо изменяя переменную напрямую через переменную экземпляра, либо внутри самого метода получателя.
Vadoff
источник
@Sakthimuthiah прав, вы должны исправить свой ответ.
Адела Тодеричи
@Sakthimuthiah неверен (и любой другой, кто говорит, что это так). Атомный НЕ делает его потокобезопасным, хотя это может быть легко ошибочно из-за его поведения. Пожалуйста, прочитайте: stackoverflow.com/questions/12347236/…
Крис J
39

Насколько я знаю, strongи retainэто синонимы, поэтому они точно делают же.

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

Это означает, что вы можете просто заменить их.

Тем не менее , есть один особый случай, с которым я столкнулся, где я должен был использовать assign, а не weak. Допустим, у нас есть два свойства delegateAssignи delegateWeak. В обоих хранится наш делегат, который владеет нами, имея единственную сильную ссылку. Делегат освобождается, поэтому и наш -deallocметод тоже вызывается.

// Our delegate is deallocating and there is no other strong ref.
- (void)dealloc {
    [delegateWeak doSomething];
    [delegateAssign doSomething];
}

Делегат уже находится в процессе освобождения, но еще не полностью освобожден. Проблема в том, что weakссылки на него уже аннулированы! Свойство delegateWeakсодержит ноль, но delegateAssignсодержит действительный объект (все свойства уже освобождены и аннулированы, но все еще действительны).

// Our delegate is deallocating and there is no other strong ref.
- (void)dealloc {
    [delegateWeak doSomething]; // Does nothing, already nil.
    [delegateAssign doSomething]; // Successful call.
}

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

Tricertops
источник
20

В документе Кланга об Objective-C Автоматический подсчет ссылок (ARC) четко разъясняются квалификаторы и модификаторы владения:

Существует четыре классификатора собственности:

  • __ autoreleasing
  • __ сильный
  • __ * unsafe_unretained *
  • __ слабый

Тип нетривиально квалифицирован как владелец, если он квалифицирован как __utoreleasing , __ strong или __ слабый .

Тогда есть шесть модификаторов собственности для объявленной собственности:

  • правопреемником подразумевает __ * unsafe_unretained * владение.
  • Копирование подразумевает ___ сильное владение, а также обычное поведение семантики копирования в установщике.
  • сохранить подразумевает __ сильную собственность.
  • сильный подразумевает __ сильный собственность.
  • * unsafe_unretained * подразумевает __ * unsafe_unretained * владение.
  • слабая подразумевает __ слабую собственность.

За исключением слабых , эти модификаторы доступны в не-ARC режимах.

В семантике квалификаторы владения имеют различное значение в пяти управляемых операциях : чтение, назначение, инициализация, уничтожение и перемещение, в которых в большинстве случаев мы заботимся только о разнице в операции назначения.

присваивание происходит при оценке оператора присваивания. Семантика варьируется в зависимости от квалификации:

  • За __ сильных объектов новый указатель сначала сохраняется; во-вторых, lvalue загружается примитивной семантикой; в-третьих, новый pointee сохраняется в lvalue с примитивной семантикой; и, наконец, старый pointee освобожден. Это не выполняется атомарно; внешняя синхронизация должна использоваться, чтобы сделать это безопасным перед лицом одновременных нагрузок и хранилищ.
  • Для __ слабых объектов значение lvalue обновляется, чтобы указывать на новый указатель, если только этот указатель не является объектом, который в настоящее время подвергается освобождению, и в этом случае значение lvalue обновляется до нулевого указателя. Это должно выполняться атомарно по отношению к другим присваиваниям объекту, чтению из объекта и окончательному выпуску нового pointee.
  • Для объектов __ * unsafe_unretained * новый pointee сохраняется в lvalue с использованием примитивной семантики.
  • Для ___ автоматически высвобождаемых объектов новый pointee сохраняется, автоматически высвобождается и сохраняется в lvalue с использованием примитивной семантики.

Другое различие в Чтении, Инициировании, Разрушении и Перемещении, пожалуйста, обратитесь к Разделу 4.2 Семантика в документе .

Mingming
источник
6

Чтобы понять сильные и слабые ссылки, рассмотрим пример ниже. Предположим, у нас есть метод с именем displayLocalVariable.

 -(void)displayLocalVariable
  {
     NSString myName = @"ABC";
     NSLog(@"My name is = %@", myName);
  }

В приведенном выше методе область действия переменной myName ограничена методом displayLocalVariable, как только метод завершится, переменная myName, содержащая строку «ABC», будет освобождена из памяти.

Теперь, что если мы хотим сохранить значение переменной myName на протяжении всего жизненного цикла контроллера представления. Для этого мы можем создать свойство с именем username, которое будет иметь ссылку Strong на переменную myName (см. self.username = myName;Код ниже), как показано ниже:

@interface LoginViewController ()

@property(nonatomic,strong) NSString* username;
@property(nonatomic,weak) NSString* dummyName;

- (void)displayLocalVariable;

@end

@implementation LoginViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

}

-(void)viewWillAppear:(BOOL)animated
{
     [self displayLocalVariable];
}

- (void)displayLocalVariable
{
   NSString myName = @"ABC";
   NSLog(@"My name is = %@", myName);
   self.username = myName;
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
}


@end

Теперь в приведенном выше коде вы можете видеть, что myName было назначено для self.username, а self.username имеет сильную ссылку (как мы объявили в интерфейсе с использованием @property) на myName (косвенно это имеет сильную ссылку на строку «ABC»). Следовательно, строка myName не будет освобождена из памяти, пока self.username не станет активным.

  • Слабая ссылка

Теперь рассмотрите возможность присвоения myName dummyName, который является слабой ссылкой, self.dummyName = myName; В отличие от Strong reference, Weak будет хранить myName только до тех пор, пока не будет Strong reference для myName. Посмотрите код ниже, чтобы понять слабую ссылку,

-(void)displayLocalVariable
  {
     NSString myName = @"ABC";
     NSLog(@"My name is = %@", myName);
     self.dummyName = myName;
  }

В приведенном выше коде есть Слабая ссылка на myName (т. Е. Self.dummyName имеет Слабую ссылку на myName), но нет строгой ссылки на myName, поэтому self.dummyName не сможет содержать значение myName.

Теперь снова рассмотрим приведенный ниже код,

-(void)displayLocalVariable
      {
         NSString myName = @"ABC";
         NSLog(@"My name is = %@", myName);
         self.username = myName;
         self.dummyName = myName;
      } 

В приведенном выше коде self.username имеет ссылку Strong на myName, поэтому self.dummyName теперь будет иметь значение myName даже после завершения метода, поскольку myName имеет ссылку Strong, связанную с ним.

Теперь всякий раз, когда мы делаем ссылку Strong на переменную, количество сохраняемых данных увеличивается на единицу, и переменная не освобождается, а количество сохраняемых данных достигает 0.

Надеюсь это поможет.

Махадев Мандале
источник
2

Strong:

  • Свойство не будет уничтожено, но только после того, как вы установите свойство равным нулю, объект будет уничтожен
  • По умолчанию все переменные экземпляра и локальные переменные являются сильными указателями.
  • Вы используете сильный, только если вам нужно сохранить объект.
  • Обычно мы используем сильный для UIViewControllers (родителей элемента пользовательского интерфейса)
  • IOS 4 (не ARC) мы можем использовать сохранить ключ
  • IOS 5 (ARC) мы можем использовать сильное ключевое слово

Пример: @property (сильный, неатомный) ViewController * viewController;

@synthesize viewController;

слабый

По умолчанию автоматически получить и установить на ноль

  • Обычно мы используем слабый для IBOutlets (UIViewController's Childs) и делегировать
  • то же самое, что присваивать, не сохранять или освобождать

Пример: @property (слабый, неатомный) IBOutlet UIButton * myButton;

@synthesize myButton;

Никунь Патель
источник
1

Различия между сильным и сохранением:

  • В iOS4 сильный равен удержанию
  • Это означает, что вы владеете объектом и держите его в куче до тех пор, пока не укажете на него.
  • Если вы напишите сохранить, он будет автоматически работать так же, как сильный

Различия между слабым и назначаемым:

  • «Слабая» ссылка - это ссылка, которую вы не сохраняете и сохраняете до тех пор, пока кто-то на нее сильно указывает
  • Когда объект «освобожден», слабый указатель автоматически устанавливается на ноль
  • Атрибут свойства «assign» сообщает компилятору, как синтезировать реализацию метода установки свойства
Чэнь Руи
источник