Есть ли разница между «переменной экземпляра» и «свойством» в Objective-c?

82

Есть ли разница между «переменной экземпляра» и «свойством» в Objective-c?

Я не очень в этом уверен. Я думаю, что «свойство» - это переменная экземпляра, у которой есть методы доступа, но я могу ошибаться.

благодаря
источник

Ответы:

84

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

@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

(Примечание: приведенный выше код ошибочен, поскольку предполагает, что имя уже существует и имеет как минимум два компонента (например, «Билл Гейтс», а не просто «Гейтс»). Я чувствовал, что исправление этих предположений сделает реальную суть кода менее ясно, поэтому я просто указываю на это здесь, чтобы никто невинно не повторил эти ошибки.)

Чак
источник
4
Способ, которым я просматривал свойство, - это средство предоставления / ограничения доступа к переменным экземпляра для внешних объектов. Что-то вроде концепции публичного / частного в других языках?
прототип
«Обычно другие объекты никогда не должны иметь к ним прямой доступ», что вы имеете в виду? Также обновлен ли ваш ответ с помощью современной objective-c?
Дорогая,
1
@Honey Я думаю, он имеет в виду концепцию инкапсуляции и следование лучшим практикам. Другие объекты не должны иметь прямого доступа или изменения ivar. Контролируя доступ к ivar через свойства, мы можем перехватывать эти вызовы до того, как они потенциально повлияют на ivar. См. Здесь для получения дополнительной информации: en.wikipedia.org/wiki/Encapsulation_(computer_programming)
user3344977
33

Свойство - это удобный способ реализации получателя / установщика некоторого значения с дополнительными полезными функциями и синтаксисом. Свойство может поддерживаться переменной экземпляра, но вы также можете определить геттер / сеттер, чтобы делать что-то более динамичное, например, вы можете определить свойство 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атрибут, чтобы отключить сеттер для свойства.

Майк Веллер
источник
1
Есть ли преимущества в объявлении переменной экземпляра и свойства (например, propertyName)? Объявление внутри интерфейса не требуется, если вы объявляете свойство для той же переменной, верно? Это действительно экономит строки кода, если я чего-то не
упускаю
6

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

Йенс Буш
источник
3

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

Переменная экземпляра - это переменная, которая существует и хранит свое значение в течение всего срока службы объекта. Память, используемая для переменных экземпляра, выделяется при первом создании объекта (посредством выделения) и освобождается при освобождении объекта.

Если не указано иное, синтезированная переменная экземпляра имеет то же имя, что и свойство, но с префиксом подчеркивания. Например, для свойства с именем firstName синтезированная переменная экземпляра будет называться _firstName.

jitenagarwal19
источник
2

Раньше люди использовали свойства публично, а ivars - для личного использования, но несколько лет назад вы также можете определять свойства, @implementationчтобы использовать их в частном порядке. Но я бы по-прежнему использовал ivars, когда это возможно, поскольку нужно вводить меньше букв, и, согласно этой статье , он работает быстрее . Это имеет смысл, поскольку свойства подразумеваются как «тяжелые»: предполагается, что к ним можно обращаться либо из сгенерированных геттеров / сеттеров, либо из тех, что написаны вручную.

Однако в последних кодах от Apple ivars больше не используются. Я думаю , потому что это больше похоже objc, чем C/C++, плюс это легче использовать свойство с assign, nullableи т.д.

superarts.org
источник
Я предполагаю, что использование свойств Apples в @implementationхочет показать сходство со Swift. Тем не менее, я также предпочитаю резервные переменные, чтобы не тратить зря вызов виртуальной функции для поиска простого поля моего собственного класса (и это происходит при доступе к свойству).
Лев