Ціль-C ARC: сильний проти збереження та слабкий проти присвоєння


367

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

Крім того copy, що, очевидно, щось зовсім інше, чи є якісь відмінності між strongvs retainі weakvs 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це достовірний атрибут, дивіться у програмі Apple "Програмування з об'єктивом-C" у розділі "Інкапсуляція даних" у підзаголовку "Використовуйте небезпечні незаповнені посилання для деяких класів". Що говорить: "Для властивості це означає використання атрибута unsafe_unretain:"
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.


11
Насправді, під ARC це помилка компіляції, яку слід використовувати assignдля об'єкта. Вам потрібно використовувати weakабо unsafe_unretained( або, що, очевидно, небезпечно), якщо ви не хочете зберігати майно.
кабал

5
assignкомпілює для мене просто в проектах ARC з ціллю розгортання 4.0.
Паскаль

8
@Pascal: слабкі посилання заборонені в цілях розгортання, коли ос не 5,0 або вище. Так що для старих проектів ви все ще можете використовувати призначення, але якщо ви переходите на новіші версії, вам доведеться перейти на слабкі
Маттія,

1
Виглядає як Xcode 4 (з ARC) генерує NSManagedObject підкласи використанням retainvs. strong. Я вважаю, що це здебільшого нешкідливо, але я думаю, що це повинно бути strongдля послідовності ... або, можливо, це не має значення. stackoverflow.com/questions/7796476/…
Джо Д'Андреа

3
@JeremyP Так, ваша відповідь точкова. Я реагував на @Mattia. Я вказував, що assignв деяких випадках все ще діє.
Стівен Окслі

606

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

  1. атомний // за замовчуванням
  2. неатомічний
  3. strong = зберегти // за замовчуванням
  4. слабкий
  5. зберегти
  6. призначити // за замовчуванням
  7. небезпечно
  8. копія
  9. лише для читання
  10. readwrite // за замовчуванням

Нижче наведено докладне посилання на статтю, де ви можете знайти вищезазначені атрибути, які точно допоможуть вам. Велике спасибі всім людям, які дають найкращі відповіді тут !!

Змінні атрибути властивості або модифікатори в iOS

1. міцний (iOS4 = зберегти)

  • в ньому написано "тримай це в купі, поки я більше не вказую на це"
  • іншими словами "Я власник, ви не можете розібратися з цим, перш ніж націлити його на те саме, що зберегти"
  • Ви використовуєте сильний лише в тому випадку, якщо вам потрібно зберегти об'єкт.
  • За замовчуванням всі змінні екземпляри та локальні змінні є сильними покажчиками.
  • Зазвичай ми використовуємо сильний для UIViewControllers (батьки елемента інтерфейсу користувача)
  • Сильний використовується з ARC, і він в основному допомагає вам, не турбуючись про кількість збережених об'єктів. ARC автоматично звільняє його для вас, коли ви закінчите з ним. Використання ключового слова сильним означає, що ви володієте об'єктом.

Приклад:

@property (strong, nonatomic) ViewController *viewController;

@synthesize viewController;

2. слабкий -

  • в ньому сказано: "Тримайте це до тих пір, поки хтось інший на це наполегливо вкаже"
  • те саме, що присвоїти, не зберегти або звільнити
  • "Слабка" посилання - це посилання, яке ви не зберігаєте.
  • Зазвичай ми використовуємо слабкі для IBOutlets (UIViewController's Childs). Це працює, оскільки дочірній об’єкт повинен існувати лише до тих пір, як це робить батьківський об'єкт.
  • слабкий довідник - це посилання, яке не захищає посилальний об'єкт від збирання сміттєзбірником.
  • Слабкий, по суті, присвоєний, невлаштований властивість. За винятком випадків, коли об'єкт розміщений, слабкий покажчик автоматично встановлюється на нуль

Приклад:

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

@synthesize myButton;

Сильне і слабке пояснення, завдяки BJ Homer :

Уявіть, наш об’єкт - собака, і що собака хоче втекти (бути розселеною).

Сильні покажчики - як повідок на собаці. Поки ви прив’язуєте повідку до собаки, собака не втече. Якщо п’ять людей прив’язують повідку до однієї собаки (п’ять сильних вказівників на один об’єкт), то собака не втече, поки всі п’ять повідців не від'єднаються.

З іншого боку, слабкі вказівники - це як маленькі діти, що вказують на собаку і говорять: "Дивись! Собака!" Поки собака все ще на повідку, маленькі діти ще можуть побачити собаку, і вони все одно вкажуть на неї. Як тільки всі повідці відриваються, собака тікає незалежно від того, скільки маленьких діток на неї вказують.

Як тільки останній сильний покажчик (повідок) більше не вказує на об’єкт, об’єкт буде розміщений, і всі слабкі покажчики будуть нульовими.

Коли ми використовуємо слабкі?

Єдиний час, коли ви хочете використовувати слабкі, це якщо ви хочете уникнути циклів утримування (наприклад, батько зберігає дитину, а дитина зберігає батьків, тому жоден з них не звільняється).

3.утримувати = сильний

  • воно зберігається, вивільняється старе значення і присвоюється утримує указує нове значення, яке слід надсилати
  • зберігати при призначенні та старе значення, надіслане -випуск
  • утримувати те саме, що сильний.
  • Apple каже, що якщо ви пишете, збережіть, воно автоматично перетвориться / працюватиме як сильний
  • такі методи, як "аллок", включають неявне "зберегти"

Приклад:

@property (nonatomic, retain) NSString *name;

@synthesize name;

4. призначити

  • призначення - це за замовчуванням і просто виконує завдання зі змінною
  • призначити атрибут властивості, який вказує компілятору, як синтезувати реалізацію властивості властивості
  • Я б використав призначати для примітивних властивостей C і слабкий для слабких посилань на об'єкти Objective-C.

Приклад:

@property (nonatomic, assign) NSString *address;

@synthesize address;

5
2. "слабке посилання - це посилання, яке не захищає посилальний об'єкт від збирання сміттєзбірником" - у об'єктиві c, як сміттєзбірник, немає такого поняття;
bucherland

1
і ця ієрархія керується iOS автоматично. Читайте про концепцію MVC. Я маю на увазі, коли ViewContorller представляє завантаження iOS, це ієрархія перегляду на екрані (створення відсутніх представлень). Коли представлено інший ViewController, ця перша ієрархія поглядів розміщується. Але якщо у ViewController у вас є "сильний", цей погляд не може бути розміщений, коли він не в екрані. Що може мати сильний вплив на пам’ять пристрою та причину уповільнення роботи додатка. (Звичайно, у пристрою багато пам’яті, і ви точно будете добре на екрані програми з 5-10 екранами, але у величезному додатку ви потрапите в проблеми)
bucherland

1
Коли ми використовуємо слабкі? 1. Для об'єктів користувальницького інтерфейсу, 2. делегати, 3. блоки (слабкий селфі слід використовувати замість самостійного, щоб уникнути циклів пам’яті (як згадувалося вище)
bucherland

1
В цій чудовій відповіді є одна помилка - сильна - "ARC автоматично звільняє її для вас, коли ви закінчите з нею", це не правильно. ARC автоматично випускає слабкі об'єкти, коли на них немає покажчиків. Сильний - синонім зберігати, тому об’єкт зберігається, і ми несемо відповідальність зробити об’єкт нульовим
Ешвін G

1
@RDC, що defaultозначає? Якщо я використовую @property (nonatomic) NSString *stringце strong? Або assign? Тому що обидва є типовими.
Юліан Онофрей

40

неатомний / атомний

  • неатомічний набагато швидше, ніж атомний
  • завжди використовуйте неатомічні, якщо ви не маєте дуже специфічної вимоги до атомних, яка повинна бути рідкісною (атомний не гарантує безпеку потоку - лише стійла, що отримують доступ до ресурсу, коли його одночасно встановлює інший потік)

сильний / слабкий / присвоїти

  • використовувати сильний для збереження об'єктів - хоча ключове слово збереження є синонімом, краще замість цього використовувати сильний
  • використовуйте слабкий, якщо ви хочете лише вказівник на об'єкт, не утримуючи його - корисний для уникнення збереження циклів (тобто делегатів) - він автоматично зніме вказівник, коли об’єкт відпущений
  • використовувати призначати для примітивів - точно так само слабко, за винятком того, що він не зводить об'єкт при звільненні (встановлено за замовчуванням)

(Необов’язково)

копія

  • використовувати його для створення дрібної копії об’єкта
  • хороша практика завжди встановлювати для копіювання незмінні властивості - оскільки змінні версії можуть бути передані у незмінні властивості, копія забезпечить, що ви завжди матимете справу з незмінним об'єктом
  • якщо переданий незмінний об'єкт, він збереже його - якщо переданий мутаційний об'єкт буде скопійовано

лише для читання

  • використовуйте його для відключення налаштування властивості (запобігає компіляції коду, якщо є порушення)
  • ви можете змінити те, що постачається getter, змінивши змінну безпосередньо через змінну його примірника, або в межах самого методу getter

@Sakthimuthiah має рацію, ви повинні виправити свою відповідь.
Адела Тодерічі

@Sakthimuthiah невірно (і всі, хто каже, що це так). Atomic НЕ робить його безпечним для потоків, хоча його можна легко помилитися через свою поведінку. Будь ласка, читайте: stackoverflow.com/questions/12347236/…
Chris J

39

Наскільки я знаю, strongі retainце синоніми, тому вони роблять точно так само.

Тоді значення weakмайже схоже assign, але автоматично встановлюється на нуль після того, як об'єкт, на який він вказує, розміщується.

Це означає, що ви можете їх просто замінити.

Однак є один особливий випадок, з яким я стикався, і мені довелося скористатися 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змінні працюють і коли вони зведені нанівець.



20

Документ Кланг про автоматичний підрахунок посилань Objective-C (ARC) чітко пояснює кваліфікатори та модифікатори власності:

Існує чотири класифікатори власності:

  • __ авторелізинг
  • __ сильний
  • __ * незахищений_незатриманий *
  • __ слабкий

Тип не належить до власних прав власності, якщо він кваліфікований з __ автоматичним вивільненням , __ сильним або __ слабким .

Тоді є шість модифікаторів власності на заявлену власність:

  • Призначати означає, що __ * unsafe_unreserved * володіння.
  • копія передбачає __ сильне володіння, а також звичайну поведінку семантики копіювання на сетері.
  • утримування означає __ сильну власність.
  • сильне означає __ сильну власність.
  • * unsafe_unreserved * передбачає __ * unsafe_unreserved * право власності.
  • слабкий означає __ слабку власність.

За винятком слабких , ці модифікатори доступні в режимах без АРК.

На думку семантики, класифікатори власності мають різний зміст у п'яти керованих операціях : "Читання", "Призначення", "Ініціалізація", "Знищення та переміщення", в яких більшість випадків ми дбаємо лише про різницю в операціях із призначенням.

Присвоєння відбувається при оцінці оператора призначення. Семантика змінюється залежно від кваліфікації:

  • Для __ сильних об'єктів новий пуантей спочатку зберігається; по-друге, lvalue завантажений примітивною семантикою; по-третє, нова пуантея зберігається в рівні значення з примітивною семантикою; і нарешті старий пуант звільнений. Це не виконується атомно; Для забезпечення безпеки в умовах одночасних навантажень і сховищ необхідно використовувати зовнішню синхронізацію.
  • Для __ слабких об'єктів lvalue оновлюється, щоб вказувати на новий pointee, за винятком випадків, коли новий pointee не є об'єктом, який зараз перебуває у взаємодії, і в цьому випадку lvalue оновлюється до нульового покажчика. Це має виконуватися атомно стосовно інших призначень об'єкту, для читання з об'єкта та остаточного виходу нового пункту.
  • Для __ * небезпечних_незатриманих * об'єктів новий pointee зберігається у lvalue за допомогою примітивної семантики.
  • Для __ autoreleasing об'єктів, новий pointee зберігається, autoreleased, і зберігається в Lvalue , використовуючи примітивну семантику.

Інша відмінність у читанні, інітації, руйнуванні та русі див. У розділі 4.2 Семантика в документі .


6

Для розуміння сильних і слабких посилань розглянемо нижче приклад, припустимо, у нас є метод, названий як displayLocalVariable.

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

У вищевказаному методі область змінної myName обмежена методом displayLocalVariable, як тільки метод закінчується, мінлива myName, яка містить рядок "ABC", буде переміщена з пам'яті.

А що робити, якщо ми хочемо утримувати значення змінної myName протягом усього життєвого циклу контролера перегляду. Для цього ми можемо створити властивість, іменоване як ім'я користувача, яке матиме чітке посилання на змінну 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"). Отже, String myName не буде розміщений з пам'яті, поки self.username живий.

  • Слабка довідка

Тепер розглянемо призначення myName в dummyName, який є слабким посиланням, self.dummyName = myName; На відміну від Сильної посилання Слабкий буде мати myName лише до тих пір, поки не буде сильного посилання на 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 має сильну посилання на нього.

Тепер, коли ми робимо сильну посилання на змінну, її кількість підрахунків збільшується на одиницю, і змінна не отримає розселену кількість підрахунків до 0.

Сподіваюсь, це допомагає.


2

Сильний:

  • Властивість не знищуватиметься, але лише після встановлення властивості на нуль об'єкт буде знищений
  • За замовчуванням всі змінні екземпляри та локальні змінні є сильними покажчиками.
  • Ви використовуєте сильний лише в тому випадку, якщо вам потрібно зберегти об'єкт.
  • Зазвичай ми використовуємо сильний для UIViewControllers (батьки елемента інтерфейсу користувача)
  • IOS 4 (не-ARC) Ми можемо використовувати утримувати KeyWord
  • IOS 5 (ARC) Ми можемо використовувати сильне ключове слово

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

@synthesize viewController;

Слабкий

За замовчуванням автоматично отримують і встановлюють нуль

  • Зазвичай ми використовуємо слабкі для IBOutlets (UIViewController's Childs) і делегуємо
  • те саме, що присвоїти, не зберегти або звільнити

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

@synthesize myButton;


1

Відмінності між сильними та утримуючими:

  • В iOS4 сильний дорівнює збереженню
  • Це означає, що ви є власником об'єкта і зберігаєте його в купі, поки більше не вказуєте на нього
  • Якщо ви пишете утримуйте, воно автоматично працюватиме так само сильно

Відмінності між слабкими і присвоюють:

  • "Слабка" посилання - це посилання, яке ви не зберігаєте, і зберігаєте його до тих пір, поки хтось інший рішуче вказує на нього
  • Коли об'єкт "розміщений", слабкий покажчик автоматично встановлюється на нуль
  • Атрибут властивості "призначити" вказує компілятору, як синтезувати реалізацію налаштування властивості
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.