it-swarm.xyz

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

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

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

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

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

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

358
Jakub Arnold

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

228
JeremyP

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

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

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

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

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

  • там написано "держи это в куче, пока я не укажу на это"
  • другими словами, "Я владелец, вы не можете сдать это, пока не нацелились на то же самое, что и удержали"
  • Вы используете сильный, только если вам нужно сохранить объект.
  • По умолчанию все переменные экземпляра и локальные переменные являются сильными указателями.
  • Обычно мы используем сильный для UIViewControllers (родители элемента UI)
  • сильный используется с 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.retain = strong

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

Пример:

@property (nonatomic, retain) NSString *name;

@synthesize name;

4.assign

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

Пример:

@property (nonatomic, assign) NSString *address;

@synthesize address;
594
swiftBoy

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

39
Tricertops

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

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

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

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

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

копия

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

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

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

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

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

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

Тип является нетривиально зависимым от владельца, если он квалифицирован с помощью __ автоматического освобождения , __ strong или __ слабо .

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

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

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

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

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

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

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

20
Mingming

Чтобы понять сильные и слабые ссылки, рассмотрим пример ниже. Предположим, у нас есть метод с именем 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 имеет ссылку Strong на myName, следовательно, self.dummyName теперь будет иметь значение myName даже после завершения метода, поскольку myName имеет ссылку Strong, связанную с ним.

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

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

4
Mahadev Mandale

Strong:

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

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

@synthesize viewController;

Слабый

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

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

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

@synthesize myButton;

2
Nikunj Patel

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

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

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

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