【iOS】Ключевое слово атрибута

Каталог статей


предисловие

В процессе обучения iOS я научился простому использованию некоторых ключевых слов-атрибутов. Сегодня в этом блоге мы обсудим это более подробно.Ключевые слова свойств в iOSа такжеОбзор глубокого и поверхностного текста


1. Глубокий и поверхностный текст

1. Какие существуют способы копирования OC

Объекты OC (типы-коллекции и типы-не-коллекции) имеют два метода копирования: поверхностное копирование и глубокое копирование.

вставьте сюда описание изображения

  • Мелкая копия: копия указателя, то есть указатели исходного объекта и объекта-копии указывают на одну и ту же область .
  • Глубокая копия: копия контента, то есть указатели исходного объекта и объекта копии указывают на две разные области .

Глубокая копия включает в себя однослойную глубокую копию и полную глубокую копию. Это будет упомянуто позже

  • Однослойная глубокая копия: слой самого объекта копирования является глубокой копией, а все объекты в нем являются поверхностными копиями.
  • Полная глубокая копия: сам объект копирования и все объекты в нем являются глубокими копиями.

Разница между поверхностной копией и глубокой копией:

  • Стоит ли открывать новое пространство памяти
  • Влияет ли это на количество ссылок?

2. Копирование и mutableCopy реализуются поверхностным или глубоким копированием объектов OC?

  • И копия, и mutableCopy изменяемых объектов (тип коллекции/тип неколлекции) являются глубокими копиями.
  • Копия неизменяемого объекта (тип коллекции/тип неколлекции) является поверхностной копией, а mutableCopy — глубокой копией.
  • Метод копирования возвращает неизменяемые объекты.
    вставьте сюда описание изображения
    Конкретный процесс реализации был описан в предыдущем блоге: [iOS] глубокое копирование и поверхностное копирование.

3. Являются ли копии и mutableCopy, реализованные пользовательским объектом, поверхностной или глубокой копией?

  • И copy, и mutableCopy пользовательских объектов являются глубокими копиями.

Поскольку наш пользовательский объект не имеет двух методов copyWithZone: и mutableCopyWithZone:, нам необходимо соблюдать протоколы SCopying и NSMutableCopying для реализации этих двух методов, которые также реализованы в приведенной выше ссылке.


4. Определить тип текущей глубокой копии? (Разница в однослойной глубокой копии или полной глубокой копии), взаимное преобразование двух типов глубокой копии?

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

  • Однослойная глубокая копия: сам объект копирования является глубокой копией, но все объекты в контейнере являются поверхностными копиями.
  • Полная глубокая копия: сам объект копирования и все объекты в нем являются глубокими копиями.

Метод реализации :

  • Однослойная глубокая копия:
    Когда объект в объекте класса контейнера является объектом класса контейнера, используйте метод initWithArray:copyItems: (второй параметр имеет значение YES ), чтобы получить однослойную неглубокую копию, поскольку эта копия может создавать только один слой глубокой копии и недопустима для второго или нескольких слоев .
  • Полная глубокая копия:
    1. Архивируйте и разархивируйте , чтобы получить полную глубокую копию.
    Пример: dataArray3 = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:dataArray2]]
    2.Когда объект в объекте класса контейнера является пользовательским объектом или не является неизменяемым объектом, используя метод initWithArray:copyItems: (второй параметр имеет значение YES ), можно добиться полной глубокой копии,
    что на самом деле здесь очень легко понять, потому что когда мы реализуем копию пользовательского объекта, нам нужно реализовать нашу copyWithZone : и mutableCopyWithZone: оба метода и копия пользовательского объекта всегда являются глубокой копией, поэтому с помощью этого метода можно получить полную глубокую копию.

5. Код следующий: Поскольку mutableCopy объекта является глубокой копией, зачем менять dataArray2 и dataArray3? Как решить эту проблему?

вставьте сюда описание изображения
вставьте сюда описание изображения

Вопрос (1). Изменяемая копия объекта является глубокой копией, так зачем менять dataArray2 и dataArray3?

dataArray3 = [dataArray2 mutableCopy];  
这段代码实现的是单层深拷贝,dataArray3是dataArray2深拷贝得到的数组,但是对于array2数组中的对象array仅仅对其进行了浅拷贝,因此更改array2时array3随之改变

Задача (2) Как решить эту задачу?

Поскольку измененный объект не является неизменяемым объектом, использование метода initWithArray:copyItems : позволяет добиться полной глубокой копии и легко решить эту проблему.

        dataArray3 = [[NSMutableArray alloc] initWithArray:dataArray2 copyItems:YES];

вставьте сюда описание изображения

6. Код показан на рисунке ниже: initWithArray:copyItems:YES может выполнять только одноуровневое глубокое копирование и недопустимо для второго или нескольких слоев. Что мне делать, если я хочу, чтобы каждый слой объекта был глубокой копией?

вставьте сюда описание изображения
вставьте сюда описание изображения
Используйте initWithArray:copyItems: глубокая копия может генерировать только один уровень глубокой копии, более глубокая копия не может быть достигнута, поэтому вам нужно использовать разархивирование и архивирование.

dataArray3 = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:dataArray2]];

Во-вторых, ключевые слова-атрибуты

@свойство

атрибут дляИнкапсулировать данные в объекты, суть свойства — ivar + setter + getter.
Свойства можно объявлять с использованием синтаксиса @property. @property поможет нам автоматически генерировать методы установки и получения свойств.объявление метода

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

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

@динамический

Скажите компилятору не использовать автоматически @synthesize, вы обеспечите реализацию этих методов во время выполнения без предупреждения, но это не повлияет на объявление методов установки и получения, сгенерированных @property.

@dynamic ivar;

Раньше нам нужно было вручную добавлять @synthesize к каждому @property, но после iOS 6 компилятор LLVM представилавтосинтез свойств, то есть атрибут синтезируется автоматически. Другими словами, компилятор автоматически добавит @synthesize к каждому @property.

Но кажется, что @synthesize бесполезен, но это не так:

  1. Если мы перепишем методы установки и получения, компилятор не будет автоматически добавлять @synthesize к этому @property, поэтому нам нужно добавить @synthesize вручную;
  2. Если свойство доступно только для чтения, то пока вы переопределите метод получения, автосинтез свойства не будет выполнен.
  3. Кроме того,Реализуйте свойства, необходимые в протоколе.. когда мыПротокол использует @property для объявления свойства. Чтобы следовать этому протоколу в классе, нам нужно использовать @synthesize в классе, чтобы получить переменную-член этого свойства и получить функцию реализации установки/получения.
    вставьте сюда описание изображения
    вставьте сюда описание изображения

Вот и протокол, давайте обсудим, может ли Category добавлять и использовать @synthesize для синтеза переменных-членов и реализации метода setget?

Ответ — нет, в нашей категории мыСвойства могут быть объявлены, но переменные-члены не могут быть объявлены.

потому чтоКатегории — это не классымы можем объявлять свойства через @property, но не можем объявлять переменные-члены

Категории используются для расширения функциональности существующих классов, а не для создания совершенно новых классов или изменения внутренней реализации классов. Таким образом, Категория не позволяет добавлять переменные экземпляра (переменные-члены) или использовать @synthesize для синтеза переменных-членов.

Следующий автор объяснит, почему Категория не может добавлять переменные экземпляра и использовать @synthesize:

  1. Объявление наших переменных экземпляра обычно необходимо поместить в файл класса, чтобы обеспечить инкапсуляцию, и, поскольку категория не является классом, Категория может добавлять только объявления методов и атрибутов, поэтому не разрешено добавлять переменные экземпляра, потому что это будет уничтожить класс.инкапсуляция.
  2. когда мыПри использовании @synthesize для синтеза переменных-членов компилятор автоматически генерирует соответствующие переменные экземпляра., поскольку Категория не может добавлять переменные экземпляра, компилятор не может генерировать соответствующие переменные экземпляра для атрибутов в Категории, поэтому @synthesize не разрешен.

Использование ключевого слова @synthesize синтезирует переменные экземпляра атрибута, а также методы получения и установки атрибута.

Вот почему мы анализируем причину, по которой Категория не может использовать @synthesize, на уровне использования кода.Затем мы анализируем причину на уровне базовой структуры :

Классификация заключается в добавлении методов классификации в список методов класса во время выполнения. Нижний уровень класса на самом деле является структурой . Классификация может добавлять атрибуты, но не может добавлять переменные-члены, поскольку переменные-члены не могут быть добавлены после структуры. Объявлен и атрибуты. Список (rw:property_array_t / ro:property_list_t) в структуру можно добавить.

Однако переменные-члены не могут быть добавлены в классификацию, а эффект наличия переменных-членов в классификации может быть реализован только косвенно через связанные объекты.Автор еще не понял эту точку знаний, и я научусь дополнять ее позже.

атомная операция

Атомарная операция: является ли атрибут атомарным, можно понимать как безопасность потока.

  • атомный

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

  • неатомный

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

Автор не получил здесь соответствующих знаний о замках, и я добавлю их, когда узнаю.

Разрешения на чтение и запись

Если разрешения на чтение и запись не записаны, по умолчанию используется чтение и запись.

  • читай пиши

Свойства имеют методы установки и методы получения.

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

только метод получения

управление памятью

Ключевые слова, относящиеся к управлению памятью, также можно понимать как управляющие символы, связанные с установщиком, а модификаторы, связанные с установщиком, указывают, как следует реализовать метод установщика.

слабый

  1. Можно только изменить тип объекта;
  2. Его можно использовать только под ARC;
  3. Модификация слабых ссылок не увеличивает количество ссылок на объекты, что в основном используется для предотвращения циклических ссылок;
  4. После освобождения слабо модифицированного объекта указатель будет автоматически установлен на ноль, и висячий указатель не будет создан;
  5. Для представлений он обычно используется на xib и раскадровке; в коде также можно использовать слабые для представлений, которые необходимо удалить, чтобы после удаления они автоматически обнулялись.

назначать

  1. Могут быть изменены как базовые типы данных, так и типы объектов;
  2. Реализация метода установки представляет собой прямое присвоение, которое обычно используется для базовых типов данных;
  3. Изменить базовые типы данных, такие как NSInteger, BOOL, int, float и т. д.;
  4. При изменении типа объекта его счетчик ссылок не увеличивается;
  5. Будет создан висячий указатель (висячий указатель: после того, как объект, измененный с помощью назначения, будет освобожден, указатель по-прежнему указывает на адрес исходного объекта, и указатель становится висячим указателем. Если вы продолжаете обращаться к исходному объекту через указатель в это время это может привести к сбою программы).

Сравнение назначенного и слабого

Тот же момент: это не влияет на счетчик ссылок объекта, то есть все они являются слабыми ссылками.
разница:

  1. Типы декорированных объектов различаются:

слабый может изменять только объекты OC (такие как UIButton, UIView и т. д.).

Назначение может изменять базовые типы данных (NSInteger, NSUInteger, CGFloat, NSTimeInterval, int, float, BOOL и т. д.) и объекты OC (если вы используете назначение для изменения объектов OC,При уничтожении объекта может быть сгенерирован висячий указатель, что приведет к сбою., не делай этого).

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

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

удерживать

  1. Используйте под MRC, в основном используйте Strong под ARC;
  2. Измените сильную ссылку, сохраните новое значение, освободите старое значение, затем установите новое значение и увеличьте счетчик ссылок нового объекта на 1;
  3. Реализация метода установки заключается в освобождении старого значения и сохранении нового значения для типов объектов OC.

Давайте подробно объясним здесь, как сохранить новое значение, освободить старое значение, а затем установить новое значение:


сильный

  1. Его можно использовать только под ARC;
  2. Принцип тот же, что и сохранение;
  3. Но при изменении блока действие Strong эквивалентно копированию, а сохранение эквивалентно назначению.

копировать

Реализация метода установки заключается в освобождении старого значения и копировании нового значения.
Обычно используется для блоков, NSString, NSArray, NSDictionary и других типов. Использование копирования или Strong для изменения блока на самом деле одно и то же. Использование копирования предназначено для поддержания согласованной записи в MRC; используется для NSString, NSArray и NSDictionary, чтобы гарантировать, что это неизменяемый объект после присвоения, чтобы избежать неожиданных результатов, вызванных внешняя модификация .


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

Вот пример:

@property (nonatomic, copy) NSString *name;

В приведенном выше кодеАтрибут name использует функцию копирования. Когда вы устанавливаете атрибут name, переданная строка копируется вместо сохранения ссылки на исходную строку. Это означает, что если исходная строка впоследствии будет изменена, значение атрибута имени не будет затронуто.

Синтетические методы доступа автоматически обрабатывают такое поведение. Например, если вы установите self.name = @"Alice", свойство name создаст копию переданной строки @"Alice" вместо того, чтобы просто хранить ссылку на @"Alice".


Разница между сильным и копирующим

Если атрибут копирования указан в объявлении атрибута, синтетический метод будет использовать метод копирования класса., обратите внимание: атрибут не имеет функции mutableCopy.Даже изменяемые переменные экземпляра используют функцию копирования, как и результат выполнения метода copyWithZone:. Итак, по соглашению создается неизменяемая копия объекта.

  • Сходства: используется для изменения объектов, которые идентифицируют отношения владения.
  • Разница: присвоение Strong означает, что несколько указателей указывают на один и тот же адрес, а копирование копии означает, что объект каждый раз копируется в память, а указатели указывают на разные адреса.
    Для неизменяемых объектов мы должны использовать модификацию копирования. Чтобы гарантировать, что строковое значение в объекте не изменится непреднамеренно, копия должна быть сделана при установке нового атрибута.

Более популярное понимание состоит в том, что при изменении атрибута с помощью Strong и присвоении ему значения его можно понимать как копию указателя , а при его изменении с помощью копирования его можно понимать как копию содержимого.

Приведем пример кода:

  • сильная модификация
NSMutableString *otherName = [[NSMutableString alloc] initWithString:@"Jack"];
Person *person = [[Person alloc] init];
person.name = otherName;
person.age = 23;

[otherName appendString:@" and Mary"];
NSLog(@"person.name = %@",person.name);
NSLog(@"%p, %p", person.name, otherName);

Мы печатаем атрибут, адрес атрибута и адрес исходного объекта соответственно:
вставьте сюда описание изображения
мы видим, что наш атрибут может быть изменен, а адрес атрибута совпадает с адресом исходного объекта, что указывает наКогда атрибут изменяется с помощью Strong, атрибут указывает на адрес памяти исходного объекта., увеличивая при этом счетчик ссылок объекта на 1

  • копировать модификацию
NSMutableString *otherName = [[NSMutableString alloc] initWithString:@"Jack"];
Person *person = [[Person alloc] init];
person.name = otherName;
person.age = 23;

[otherName appendString:@" and Mary"];
NSLog(@"person.name = %@",person.name);
NSLog(@"person.name = %@",otherName);
NSLog(@"%p, %p", person.name, otherName);

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

Видно, что адрес, на который указывает наш атрибут, отличается от адреса исходного объекта, и данные в пространстве памяти, на которое указывает наш атрибут, не были изменены, но были изменены данные исходного объекта. указывая на то, чтоНовое пространство памяти будет создано при изменении атрибута с помощью копии и присвоении ему значения.Атрибут указывает на вновь созданное пространство памяти, которое на самом деле является копией содержимого (глубокая копия).

Использование сильных и копируемых ключевых слов.

Атрибуты @property используют копию для изменения неизменяемых объектов и Strong для изменения изменяемых объектов.

1. Часто используемые базовые типы соответствуют типам данных Foundation?

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

  • int -> NSInteger
  • без знака -> NSUInteger
  • плавающее -> CGFloat
  • время анимации -> NSTimeInterval

2. Определить формат атрибута? (порядок модификаторов при определении свойств?)

Рекомендуется определять атрибуты в следующем формате

@property (nonatomic, readwrite, copy) NSString *name;

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

3. Какой атрибут @property по умолчанию используется в ARC?

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

4. Что означают ключевые слова разрешения на чтение и запись атрибута?

Разрешения на чтение и запись

readwrite: доступен для чтения и записи, модификатор по умолчанию.Геттеры и сеттеры генерируются автоматически..
только для чтения: только чтение.Будут созданы только геттеры, но не сеттеры.

5. Что означает ключевое слово атомарной операции атрибута?

Атомарная операция: является ли атрибут атомарным, можно понимать как безопасность потока.

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

неатомный: Неатомарный, непрактичный для блокировок синхронизации.
Обычно при объявлении свойств устанавливается неатомарность. Использование неатомарных данных может улучшить производительность доступа.

Здесь заложены некоторые знания по замкам, но я их еще не усвоил и дополню позже

6. Какую модификацию ключевого слова следует использовать делегату?

Период MRC: используйте назначение , которое не приведет к циклическим ссылкам, но его необходимо освободить вручную.
Период ARC: лучше всего использовать слабый , если вы используете назначение, вам нужно освободить его вручную. Если логика выпуска не написана, то при уничтожении страницы объект делегата, скорее всего, станет недействительным, что приведет к сбою программы.

7. Что не так с объявлением следующих атрибутов? Если это должно быть определено таким образом, как изменить его, чтобы оно было правильным?

@property (nonatomic, copy) NSMutableArray *mutableArray;

Если мы выполним такие операции, как добавление, удаление и изменение атрибутов, программа выйдет из строя, потому что, когда мы присваиваем значения атрибутам,copy копирует неизменяемый объект NSArray

Конкретный анализ: ключевое слово copy не следует использовать для изменения объектов переменных.
Атрибут, измененный копированием, копирует объект в память, то есть два указателя указывают на разные адреса памяти.
Типы объектов переменных, предоставляемые платформой Foundation, реализовали протокол NSCopying.Таким образом, использование метода копирования возвращает неизменяемые объекты..
В этом вопросе массив переменных модифицируется с помощью ключевого слова copy, тогда при присвоении значения этому свойству будет получен неизменяемый массив типа NSArray.
Поскольку это тип NSArray, то есть неизменяемый тип массива, поэтому, если функция добавления, удаления и изменения массива переменных выполняется над атрибутом, это приведет к сбою.

Итак, правильный способ записи следующий:
@property (nonatomic, strong) NSMutableArray *mutableArray;


Если нам необходимо использовать копирование, нам нужно переписать метод установки, потому что, когда атрибуту присваивается модификация копии, метод установки будет автоматически вызываться для выполнения метода copyWithZone:, который возвращает неизменяемый объект, поэтому нам нужно его изменить. следующее:

// .h文件
@property (nonatomic, copy) NSMutableArray *mutableArray;

// .m文件
// 重写setter⽅法 使_mutableArray变为可变的copy
- (void)setMutableArray:(NSMutableArray *)mutableArray {
    
    
    _mutableArray = [mutableArray mutableCopy]; 
}

- (void )viewDidLoad {
    
     
    [super viewDidLoad];
    NSMutableArray *array = [NSMutableArray arrayWithObjects:@1, @2, nil]; self.mutableArray = array;
    [self.mutableArray removeObjectAtIndex:0]; 
    NSLog(@"self.mutableArray:%@", self.mutableArray);
}

输出:
self.mutableArray:( 2
)

8. Почему атрибут @property использует копию для изменения неизменяемых объектов, а сильный — для изменения переменных объектов?

  • Украсьте неизменяемые объекты копией:

Атрибут, измененный копированием, копирует объект в память, то есть два указателя указывают на разные адреса памяти.
Типы объектов, предоставляемые платформой Foundation, реализовали протокол NSCopying, поэтому все неизменяемые объекты возвращаются с использованием метода копирования.
Даже если исходный объект является изменяемым объектом (объект, используемый для реализации свойства, является изменяемым), скопированный объект не изменится соответствующим образом .
Это гарантирует, что объекты не могут быть изменены случайно.

  • Используйте Strong для изменения изменяемых объектов:

Атрибут, измененный с помощью Strong, является строгой ссылкой на атрибут, то есть два указателя будут указывать на один и тот же адрес памяти.
Если исходный объект является изменяемым, объект, измененный с помощью Strong, также изменится соответствующим образом.

Подведем итог

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

Guess you like

Origin blog.csdn.net/weixin_72437555/article/details/132611452
ios