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

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

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

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

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

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

Ответы [ 8 ]

594 голосов
/ 21 марта 2013

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

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

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

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

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

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

Пример: * * тысяча пятьдесят-три

@property (strong, nonatomic) ViewController *viewController;

@synthesize viewController;

2.weak -

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

Пример:

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

@synthesize myButton;

Сильное и слабое объяснение, Благодаря Би Джей Гомеру :

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

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

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

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

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

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

3.retain = strong

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

Пример:

@property (nonatomic, retain) NSString *name;

@synthesize name;

4.assign

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

Пример:

@property (nonatomic, assign) NSString *address;

@synthesize address;
228 голосов
/ 19 января 2012

От Переход к примечаниям к выпуску 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.

39 голосов
/ 27 января 2013

Насколько я знаю, 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 переменные и когда они обнуляются.

38 голосов
/ 08 октября 2014

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

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

сильный / слабый / назначения

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

(опционально)

копия

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

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

  • использовать его, чтобы отключить настройку свойства (предотвращает компиляцию кода при нарушении)
  • вы можете изменить то, что доставляет получатель, либо изменяя переменную напрямую через переменную экземпляра, либо внутри самого метода получателя
20 голосов
/ 22 октября 2013

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

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

  • __ автоматический выпуск
  • __ сильный
  • __ * unsafe_unretained *
  • __ слабый

Тип нетривиально квалифицирован с правом собственности, если он квалифицирован с __ автоматическим выпуском , __ сильным или __ слабым .

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

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

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

С точки зрения семантики квалификаторы владения имеют различное значение в пять управляемых операций : Чтение, Присвоение, Инициализация, Разрушение и Перемещение, в которых в большинстве случаев мы заботимся только о разнице в операции Присвоения.

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

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

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

4 голосов
/ 11 октября 2018

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

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

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

А что если мы хотим сохранить значение переменной myName в течение всего жизненного цикла контроллера представления.Для этого мы можем создать свойство с именем username, которое будет иметь строгую ссылку на переменную 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 имеет строгую ссылку на myName, следовательно, self.dummyNameтеперь будет иметь значение myName даже после завершения метода, так как с myName связана ссылка Strong, связанная с ним.

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

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

2 голосов
/ 26 января 2017

Strong:

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

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

@ синтезировать viewController;

Слабые

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

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

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

@ synthesize myButton;

1 голос
/ 26 апреля 2015

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

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

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

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