Чи існує різниця між “змінною екземпляра” та “властивістю” в 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
Те, як я переглядав властивості, є засобом забезпечення / обмеження доступу до змінних екземпляра для зовнішніх об'єктів. Начебто державне / приватне поняття іншими мовами?
прототип

"Зазвичай інші об'єкти ніколи не повинні отримувати до них безпосередній доступ", що ви маєте на увазі під цим? Також ваша відповідь оновлена ​​сучасним завданням-c?
Мед

1
@Honey Я думаю, що він посилається на концепцію інкапсуляції та дотримується найкращих практик. Інші об’єкти не повинні мати можливості безпосереднього доступу до ivar або його модифікації. Керуючи доступом ivar через властивості, ми можемо перехопити ці дзвінки, перш ніж вони потенційно вплинуть на ivar. Дивіться тут для отримання додаткової інформації: en.wikipedia.org/wiki/Encapsulation_(computer_programming)
user3344977

33

Властивість - це дружній спосіб реалізації геттера / сеттера для певного значення, з додатковими корисними функціями та синтаксисом. Властивість може бути підтримана змінною екземпляра, але ви також можете визначити getter / setter, щоб зробити щось більш динамічне, наприклад, ви можете визначити властивість 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вас, ви дійсно викликаєте setter / getter методи на об'єкті.

@synthesizeРядок вказує компілятору генерувати ці геттер / сеттери для вас, з допомогою змінної - члена з тим же ім'ям властивості для зберігання значення (або otherVarNameякщо ви використовуєте синтаксис в коментарях).

Поряд з цим @synthesizeви все ще можете замінити одного з геттерів / установників, визначивши свій власний. Правила іменування для цих методів призначені setPropertyName:для сеттера та propertyName(або getPropertyName, не стандартно) для геттера. Інший все одно буде створений для вас.

У вашому @propertyрядку ви можете визначити ряд атрибутів у паренах для властивості, які можуть автоматизувати такі речі, як безпека потоків та управління пам'яттю. За замовчуванням властивість атомарне, тобто компілятор оберне @synthesizвиклики get / set із відповідними блокуваннями, щоб запобігти проблемам паралельності. Ви можете вказати nonatomicатрибут, щоб вимкнути це (наприклад, на iPhone, для якого потрібно встановити більшість властивостей за замовчуванням nonatomic).

Існує 3 значення атрибутів, які контролюють управління пам’яттю для будь-яких @synthesizedустановників. Перший - retainце автоматичний releaseперехід до старих значень властивості та retainдо нових значень. Це дуже корисно.

Другий - copyце скопіювати будь-які передані значення, а не зберегти їх. Корисно використовувати copyNSString, оскільки абонент може передати NSMutableString і змінити його з-під вас. copyзробить нову копію вводу, доступ до якого ви маєте лише ви.

Третій - assignце присвоєння прямого вказівника без виклику retain / release на старому або новому об'єкті.

Нарешті, ви також можете використовувати readonlyатрибут, щоб вимкнути сеттер для властивості.


1
Чи є якась вигода від оголошення змінної екземпляра та властивості (наприклад, propertyName)? Декларація всередині інтерфейсу не потрібна, якщо ви оголошуєте властивість для тієї ж змінної, правильно? Це дійсно економить на рядках коду, якщо я чогось не пропускаю ..
whyoz

6

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


3

За замовчуванням властивість readwrite підтримується змінною екземпляра, яка знову синтезується автоматично компілятором.

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

Якщо не вказано інше, синтезована змінна екземпляра має те саме ім’я, що і властивість, але з префіксом підкреслення. Наприклад, для властивості, що називається firstName, синтезована змінна екземпляра буде називатися _firstName.


2

Раніше люди використовували властивості публічно, а ivars - для приватного використання, але, оскільки кілька років тому, ви також можете визначити властивості, @implementationщоб використовувати їх приватно. Але я все одно використовую ivars, коли це можливо, оскільки букв для введення менше, і він працює швидше відповідно до цієї статті . Це має сенс, оскільки властивості мають бути «важкими»: доступ до них передбачається або згенерованих геттерів / сеттерів, або тих, які написані вручну.

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


Я припускаю, що використання властивостей Яблуками в @implementationхоче показати схожість із Swift. Тим не менше, я також віддаю перевагу резервним змінним, щоб не витрачати виклик віртуальної функції, щоб шукати просте поле мого власного класу (і це трапляється при зверненні до властивості).
Лев
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.