@property сохранить, назначить, скопировать, неатомный в Objective-C

214

Как кто-то, кто плохо знаком с Objective-C, может ли кто-нибудь дать мне обзор сохранения, назначения, копирования и любых других, которые мне не хватает, которые следуют директиве @property? Что они делают и почему я хочу использовать один поверх другого?

Марк Рейд
источник
1
Название Apple для них - "атрибуты" или "атрибуты свойств"
Неван Кинг

Ответы:

274

Статья, на которую ссылается MrMage, больше не работает. Итак, вот что я узнал из моего (очень) короткого времени программирования в Objective-C:

nonatomic vs. atomic - по умолчанию используется "atomic". Всегда используйте «неатомные». Я не знаю почему, но в книге, которую я прочитал, сказано, что есть «редко» причина использовать «атомарный». (Кстати: книга, которую я прочитал - это книга BNR "Программирование на iOS".)

readwrite против readonly - «readwrite» используется по умолчанию. Когда вы @synthesize, для вас будут созданы и геттер, и сеттер. Если вы используете «только чтение», сеттер не будет создан. Используйте его для значения, которое вы не хотите изменять после создания экземпляра объекта.

сохранить против копирования против присвоения

  • «Назначить» является значением по умолчанию. В установщике, созданном @synthesize, значение будет просто присвоено атрибуту. Насколько я понимаю, «назначить» следует использовать для не указателей атрибутов.
  • «retain» необходим, когда атрибут является указателем на объект. Сеттер, сгенерированный @synthesize, сохранит (или добавит счетчик сохранения) объект. Вам нужно будет отпустить объект, когда вы закончите с ним.
  • «копия» необходима, когда объект изменчив. Используйте это, если вам нужно, чтобы значение объекта было таким, как оно есть в данный момент, и вы не хотите, чтобы это значение отражало какие-либо изменения, сделанные другими владельцами объекта. Вам нужно будет освободить объект, когда вы закончите с ним, потому что вы сохраняете копию.
Blamdarot
источник
@Blamdarot - мне нужно также выпустить его с ARC
Dejell
10
@ Odelya - Нет. Если вы выпустите во время использования ARC, я думаю, вы получите ошибку компилятора.
Blamdarot
53
«Всегда используйте неатомные» - плохой совет. Вы должны знать, что вы отказываетесь, когда вы используете неатомные.
Джесси Русак
7
Согласовано. В частности, многие люди, кажется, не знают, что неатомарные значения не сохраняются-автоматически высвобождаются получателем. неатомичное часто уместно, но программирование культа грузов редко.
Cat_Man
9
Советовать оставить значение по умолчанию atomicтак же плохо, как советовать nonatomic. Ни один из вариантов не является «правильным», поэтому разработчики языка выбрали более безопасное из двух решений. На самом деле, nonatomicкак правило, это лучший выбор, поскольку он исключает чрезвычайно дорогие блокировки потоков. Единственная причина для использования atomic- если ваше свойство может быть установлено из нескольких потоков (в этом случае его пропуск может привести к перерасходу или утечке).
Адам Каплан
295

Прежде чем вы узнаете об атрибутах @property, вы должны знать, что такое @property.

  • @property предлагает способ определить информацию, которую класс должен инкапсулировать. Если вы объявите объект / переменную с помощью @property , то этот объект / переменная будет доступен для других классов, импортирующих его класс.

  • Если вы объявляете объект с помощью @property в заголовочном файле, то вы должны синтезировать его с помощью @synthesize в файле реализации. Это делает объект KVC-совместимым . По умолчанию компилятор синтезирует методы доступа для этого объекта.

  • Методы доступа: сеттер и геттер.

Пример: .h

@interface XYZClass : NSObject
@property (nonatomic, retain) NSString *name;
@end

.m

@implementation XYZClass
@synthesize name;
@end

Теперь компилятор будет синтезировать методы доступа для имени .

XYZClass *obj=[[XYZClass alloc]init];
NSString *name1=[obj name]; // get 'name'
[obj setName:@"liza"]; // first letter of 'name' becomes capital in setter method
  • Список атрибутов @property

    атомарный, неатомный, сохранить, скопировать, только для чтения, перезаписать, назначить, сильный, getter = метод, setter = метод, unsafe_unretained

  • атомарное поведение по умолчанию. Если объект объявлен как атомарный, он становится потокобезопасным. Потокобезопасный означает, что одновременно только один поток конкретного экземпляра этого класса может иметь контроль над этим объектом.

Если поток выполняет метод получения, тогда другой поток не может выполнить метод установки для этого объекта. Это медленно.

@property NSString *name; //by default atomic`
@property (atomic)NSString *name; // explicitly declared atomic`
  • неатомный не является потокобезопасным. Вы можете использовать атрибут неатомного свойства, чтобы указать, что синтезированные средства доступа просто устанавливают или возвращают значение напрямую, без каких-либо гарантий относительно того, что произойдет, если к одному и тому же значению обращаются одновременно из разных потоков.

По этой причине доступ к неатомарному свойству быстрее, чем к атомарному.

@property (nonatomic)NSString *name;   
  • retain требуется, когда атрибут является указателем на объект.

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

@property (retain)NSString *name;
  • копия Если вы используете копию, вы не можете использовать сохранить. Использование экземпляра экземпляра класса будет содержать свою собственную копию.

Даже если изменяемая строка установлена ​​и впоследствии изменена, экземпляр захватывает любое значение, которое он имеет во время его установки. Методы получения и получения не будут синтезированы.

@property (copy) NSString *name;

сейчас,

NSMutableString *nameString = [NSMutableString stringWithString:@"Liza"];    
xyzObj.name = nameString;    
[nameString appendString:@"Pizza"]; 

имя останется без изменений.

  • readonly Если вы не хотите разрешать изменение свойства с помощью метода setter, вы можете объявить свойство только для чтения.

Компилятор будет генерировать геттер, но не сеттер.

@property (readonly) NSString *name;
  • readwrite - это поведение по умолчанию. Вам не нужно явно указывать атрибут readwrite.

Это противоположно только для чтения.

@property (readwrite) NSString *name;
  • assign создаст установщик, который присваивает значение переменной экземпляра напрямую, а не копирует или сохраняет его. Это лучше всего подходит для примитивных типов, таких как NSInteger и CGFloat, или для объектов, которыми вы не владеете напрямую, таких как делегаты.

Имейте в виду, что функции сохранения и назначения в принципе взаимозаменяемы, когда включена сборка мусора.

@property (assign) NSInteger year;
  • Сильный является заменой для удержания.

Это идет с ARC.

@property (nonatomic, strong) AVPlayer *player; 
  • getter = method Если вы хотите использовать другое имя для метода getter, можно указать пользовательское имя, добавив атрибуты в свойство.

В случае логических свойств (свойств, имеющих значение YES или NO), метод getter обычно начинается со слова «is»

@property (getter=isFinished) BOOL finished;
  • setter = метод Если вы хотите использовать другое имя для метода сеттера, можно указать пользовательское имя, добавив атрибуты в свойство.

Метод должен заканчиваться двоеточием.

@property(setter = boolBool:) BOOL finished;
  • unsafe_unretained В Какао и Какао Touch есть несколько классов, которые еще не поддерживают слабые ссылки, что означает, что вы не можете объявить слабое свойство или слабую локальную переменную, чтобы отслеживать их. Эти классы включают NSTextView, NSFont и NSColorSpace и т. Д. Если вам нужно использовать слабую ссылку на один из этих классов, вы должны использовать небезопасную ссылку.

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

@property (unsafe_unretained) NSObject *unsafeProperty;

Если вам нужно указать несколько атрибутов, просто включите их в список через запятую, например так:

@property (readonly, getter=isFinished) BOOL finished;
Лиза
источник
Кроме того, слабый означает, что не существует счетчика ссылок на ссылку на объект, но на него ссылаются вообще или вообще не ссылаются. Что-то вроде «да, что-то ссылалось на меня» против «9 ссылок на меня существуют» (на что это похоже).
Алекс Заватоне
6
Не обращайте внимания на строку в ответе относительно сбора мусора, поскольку сборка мусора устарела в Mac OS X и отсутствует в iOS согласно документации Apple .
Базилик Бурк
4
«Примечание: атомарность свойства не является синонимом безопасности потока объекта». - от developer.apple.com/library/mac/documentation/Cocoa/Conceptual/…
jk7
1
«Если вы объявляете объект, используя @propertyв заголовочном файле, то вы должны синтезировать его, используя @synthesizeв файле реализации». Не всегда. Например: «По умолчанию readwriteсвойство будет поддерживаться переменной экземпляра, которая снова будет автоматически синтезироваться компилятором». Из док .
Франклин Ю
4
@liza Это отличный ответ. Почему это не принятый ответ. Это дает гораздо более осведомленное объяснение, чем принятый в настоящее время ответ. Я не понимаю, StackOverflow иногда?
Чарльз Робертсон
149

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

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

Ниже приведена ссылка на подробную статью, где вы можете найти эти атрибуты.

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

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

Вот пример описания из статьи

  1. atomic -Atomic означает, что только один поток обращается к переменной (статический тип). -Атомный потокобезопасный. -но это медленно в производительности -атомное поведение по умолчанию -атомные аксессоры в среде без сборки мусора (т.е. при использовании retain / release / autorelease) будут использовать блокировку, чтобы гарантировать, что другой поток не мешает правильной настройке / получению стоимости. -это на самом деле не ключевое слово.

Пример :

@property (retain) NSString *name;

@synthesize name;
  1. nonatomic -Nonatomic означает многопоточный доступ к переменной (динамический тип). -Nonatomic это поток небезопасно. -но это быстро в производительности -Nonatomic не является поведением по умолчанию, нам нужно добавить неатомическое ключевое слово в атрибуте свойства. -это может привести к неожиданному поведению, когда два разных процесса (потока) обращаются к одной и той же переменной одновременно.

Пример:

@property (nonatomic, retain) NSString *name;

@synthesize name;

Объясните:

Предположим, что есть атомарное строковое свойство с именем «name», и если вы вызываете [self setName: @ «A»] из потока A, вызываете [self setName: @ "B»] из потока B и вызываете [self name] из поток C, тогда все операции в другом потоке будут выполняться последовательно, что означает, что если один поток выполняет установщик или получатель, то другие потоки будут ожидать. Это делает свойство «name» доступным для чтения / записи, но если другой поток D одновременно вызывает [name release], то эта операция может привести к сбою, так как здесь нет никакого вызова setter / getter. Это означает, что объект является безопасным для чтения / записи (ATOMIC), но не потокобезопасным, поскольку другие потоки могут одновременно отправлять объекту сообщения любого типа. Разработчик должен обеспечить безопасность потоков для таких объектов.

Если свойство "name" было неатомичным, то все потоки в приведенном выше примере - A, B, C и D будут выполняться одновременно, что приведет к непредсказуемому результату. В случае атомарного, любой из A, B или C будет выполняться первым, но D все еще может выполняться параллельно.

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

Пример:

@property (strong, nonatomic) ViewController *viewController;

@synthesize viewController;
  1. Слабый (iOS4 = unsafe_unretained) - он говорит: «держите это, пока кто-то другой строго на него указывает» - то же самое, что назначить, не сохранять или освобождать - «Слабая» ссылка - это ссылка, которую вы не сохраняете. -Мы обычно используем слабый для IBOutlets (Childs UIViewController). Это работает, потому что дочерний объект должен существовать только столько, сколько родительский объект делает. -слабая ссылка - это ссылка, которая не защищает указанный объект от сбора сборщиком мусора. -Слабость, по сути, присваивать, оставленное свойство. За исключением случаев, когда объект освобожден, слабый указатель автоматически устанавливается на ноль

Пример :

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

@synthesize myButton;

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

Представьте, что наш объект - собака, и что собака хочет убежать (быть освобожденной). Сильные указатели похожи на поводок на собаку. Пока вы привязали поводок к собаке, собака не убежит. Если пять человек прикрепят поводок к одной собаке (пять сильных указателей на один объект), то собака не убежит, пока все пять поводков не отсоединятся. Слабые указатели, с другой стороны, похожи на маленьких детей, указывающих на собаку и говорящих "Смотри! Собака!" Пока собака все еще на поводке, маленькие дети все еще могут видеть собаку, и они все еще будут указывать на нее. Однако, как только поводки отстегнуты, собака убегает независимо от того, сколько на нее указывают маленькие дети. Как только последний сильный указатель (поводок) перестанет указывать на объект, объект будет освобожден, а все слабые указатели будут обнулены. Когда мы используем слабые? Единственный раз, когда вы захотите использовать слабый, - это если вы хотите избежать циклов сохранения (например, родитель сохраняет ребенка, а ребенок сохраняет родителя, поэтому ни один из них никогда не освобождается).

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

Пример:

@property (nonatomic, retain) NSString *name;

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

Пример:

@property (nonatomic, assign) NSString *address;

@synthesize address;
  1. unsafe_unretained

    -unsafe_unretained - квалификатор владения, который сообщает ARC, как вставлять вызовы сохранения / освобождения. -unsafe_unretained - это версия ARC назначения.

Пример:

@property (nonatomic, unsafe_unretained) NSString *nickName;

@synthesize nickName;
  1. copy -copy требуется, когда объект изменчив. -copy указывает, что новое значение должно быть отправлено -copy при назначении, а старое значение отправлено -release. -copy похоже на то, что retain возвращает объект, который вы должны явно освободить (например, в dealloc) в средах без сбора мусора. -Если вы используете копию, вам все равно нужно выпустить ее в dealloc. -Используйте это, если вам нужно, чтобы значение объекта было таким, как оно есть в данный момент, и вы не хотите, чтобы это значение отражало какие-либо изменения, сделанные другими владельцами объекта. Вам нужно будет освободить объект, когда вы закончите с ним, потому что вы сохраняете копию.

Пример:

@property (nonatomic, copy) NSArray *myArray;

@synthesize myArray;
swiftBoy
источник
2
Я думаю, что после дуги, сохранение больше не используется.
Mert
1
полный список пропускает 2 элемента опций: setter и getter, которые также являются единственными опциями, нуждающимися в аргументе.
Скотт Чу
Сильный или сохранить по умолчанию только для типа объекта. Его нельзя использовать для примитивных типов.
Салех Энам Шохаг
9

Атомарное свойство может быть доступно только одному потоку за раз. Это потокобезопасно . По умолчанию атомарный. Обратите внимание, что ключевое слово atomic отсутствует.

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

Поэтому нужно быть очень осторожным при использовании атомарного. Как это влияет на производительность вашего кода

Каннан Прасад
источник
3
«Примечание: атомарность свойства не является синонимом безопасности потока объекта». от developer.apple.com/library/mac/documentation/Cocoa/Conceptual/…
jk7