Есть ли разница между «переменной экземпляра» и «свойством» в Objective-c?
Я не очень в этом уверен. Я думаю, что «свойство» - это переменная экземпляра, у которой есть методы доступа, но я могу ошибаться.
Ответы:
Свойство - это более абстрактное понятие. Переменная экземпляра - это буквально просто слот для хранения, как слот в структуре. Обычно другие объекты никогда не должны обращаться к ним напрямую. С другой стороны, свойство - это атрибут вашего объекта, к которому можно получить доступ (это звучит расплывчато, и так должно быть). Обычно свойство возвращает или устанавливает переменную экземпляра, но оно может использовать данные из нескольких или вообще ни одного. Например:
@interface Person : NSObject {
NSString *name;
}
@property(copy) NSString *name;
@property(copy) NSString *firstName;
@property(copy) NSString *lastName;
@end
@implementation Person
@synthesize name;
- (NSString *)firstName {
[[name componentsSeparatedByString:@" "] objectAtIndex:0];
}
- (NSString *)lastName {
[[name componentsSeparatedByString:@" "] lastObject];
}
- (NSString *)setFirstName:(NSString *)newName {
NSArray *nameArray = [name componentsSeparatedByString:@" "];
NSArray *newNameArray [[NSArray arrayWithObjects:newName, nil] arrayByAddingObjectsFromArray:[nameArray subarrayWithRange:NSMakeRange(1, [nameArray size]-1)]];
self.name = [newNameArray componentsJoinedByString:@" "];
}
- (NSString *)setLastName:(NSString *)newName {
NSArray *nameArray = [name componentsSeparatedByString:@" "];
NSArray *newNameArray [[nameArray subarrayWithRange:NSMakeRange(0, [nameArray size]-2)] arrayByAddingObjectsFromArray:[NSArray arrayWithObjects:newName, nil]];
self.name = [newNameArray componentsJoinedByString:@" "];
}
@end
(Примечание: приведенный выше код ошибочен, поскольку предполагает, что имя уже существует и имеет как минимум два компонента (например, «Билл Гейтс», а не просто «Гейтс»). Я чувствовал, что исправление этих предположений сделает реальную суть кода менее ясно, поэтому я просто указываю на это здесь, чтобы никто невинно не повторил эти ошибки.)
Свойство - это удобный способ реализации получателя / установщика некоторого значения с дополнительными полезными функциями и синтаксисом. Свойство может поддерживаться переменной экземпляра, но вы также можете определить геттер / сеттер, чтобы делать что-то более динамичное, например, вы можете определить свойство lowerCase в строке, которая динамически создает результат, а не возвращает значение какого-либо члена переменная.
Вот пример:
// === In your .h ===
@interface MyObject {
NSString *propertyName;
}
// ...
@property (nonatomic, retain) NSString *propertyName;
// === In your .m @implementation ===
@synthesize propertyName /* = otherVarName */;
@propertyСтрока определяет свойство propertyNameтипа NSString *. Это можно получить / установить, используя следующий синтаксис:
myObject.propertyName = @"Hello World!";
NSLog("Value: %@", myObject.propertyName);
Когда вы назначаете или читаете из, myObject.propertyNameвы действительно вызываете методы установки / получения объекта.
@synthesizeСтрока указывает компилятору генерировать эти геттер / сеттеры для вас, с помощью переменной - члена с тем же именем свойства для хранения значения (или otherVarNameесли вы используете синтаксис в комментариях).
Наряду с этим @synthesizeвы все еще можете переопределить один из геттеров / сеттеров, определив свой собственный. Соглашение об именах для этих методов предназначено setPropertyName:для установщика и propertyName(или getPropertyNameне стандартно) для получателя. Другой по-прежнему будет создан для вас.
В своей @propertyстроке вы можете определить ряд атрибутов в скобках для свойства, которые могут автоматизировать такие вещи, как безопасность потоков и управление памятью. По умолчанию свойство является атомарным, что означает, что компилятор обертывает @synthesizвызовы get / set соответствующими блокировками, чтобы предотвратить проблемы параллелизма. Вы можете указать nonatomicатрибут, чтобы отключить это (например, на iPhone вы хотите установить большинство свойств по умолчанию nonatomic).
Есть 3 значения атрибута, которые контролируют управление памятью для любых @synthesizedустановщиков. Первый из retainних автоматически отправляет releaseстарые значения свойства и retainновые значения. Это очень полезно.
Второй - copyэто копирование любых переданных значений, а не их сохранение. Рекомендуется использовать copyдля NSString, потому что вызывающий может передать NSMutableString и изменить его из-под вас. copyсоздаст новую копию ввода, доступ к которой есть только у вас.
Третий - assignэто назначение прямого указателя без вызова функции сохранения / освобождения для старого или нового объекта.
Наконец, вы также можете использовать readonlyатрибут, чтобы отключить сеттер для свойства.
По умолчанию свойство readwrite будет поддерживаться переменной экземпляра, которая снова будет автоматически синтезирована компилятором.
Переменная экземпляра - это переменная, которая существует и хранит свое значение в течение всего срока службы объекта. Память, используемая для переменных экземпляра, выделяется при первом создании объекта (посредством выделения) и освобождается при освобождении объекта.
Если не указано иное, синтезированная переменная экземпляра имеет то же имя, что и свойство, но с префиксом подчеркивания. Например, для свойства с именем firstName синтезированная переменная экземпляра будет называться _firstName.
Раньше люди использовали свойства публично, а ivars - для личного использования, но несколько лет назад вы также можете определять свойства, @implementationчтобы использовать их в частном порядке. Но я бы по-прежнему использовал ivars, когда это возможно, поскольку нужно вводить меньше букв, и, согласно этой статье , он работает быстрее . Это имеет смысл, поскольку свойства подразумеваются как «тяжелые»: предполагается, что к ним можно обращаться либо из сгенерированных геттеров / сеттеров, либо из тех, что написаны вручную.
Однако в последних кодах от Apple ivars больше не используются. Я думаю , потому что это больше похоже objc, чем C/C++, плюс это легче использовать свойство с assign, nullableи т.д.
@implementationхочет показать сходство со Swift. Тем не менее, я также предпочитаю резервные переменные, чтобы не тратить зря вызов виртуальной функции для поиска простого поля моего собственного класса (и это происходит при доступе к свойству).