Свойства только для класса и его подклассов - PullRequest
20 голосов
/ 24 ноября 2010

Можно ли определить свойства, которые доступны только для класса, в котором они определены, и подклассов этого класса?

Другими словами, есть ли способ определить защищенные свойства?

Ответы [ 3 ]

15 голосов
/ 24 ноября 2010

Технически, нет.Свойства на самом деле являются просто методами, и все методы являются открытыми.Способ, которым мы «защищаем» методы в Objective-C, заключается в том, чтобы не сообщать о них другим людям.Вы можете определить свойства в расширении класса, и все же @synthesize их в своем основном блоке реализации.

10 голосов
/ 06 февраля 2014

Это возможно при использовании расширения класса (не категории), которое вы включаете в файлы реализации базового класса и подклассов.

Расширение класса определяется аналогично категории, но без категорииname:

@interface MyClass ()

В расширении класса вы можете объявить свойства, которые смогут синтезировать вспомогательные ivars (XCode> 4.4, автоматический синтез ivars также работает здесь).

В классе расширений вы можете переопределить / уточнить свойства (изменить только чтение на чтение и т. Д.) И добавить свойства и методы, которые будут «видимы» для файлов реализации (но обратите внимание, что свойства и методы на самом деле не являются частными и могутвсе еще вызывается селектором).

Другие предложили использовать для этого отдельный заголовочный файл MyClass_protected.h, но это также можно сделать в главном заголовочном файле, используя #ifdef, например:

Пример:

BaseClass.h

@interface BaseClass : NSObject

// foo is readonly for consumers of the class
@property (nonatomic, readonly) NSString *foo;

@end


#ifdef BaseClass_protected

// this is the class extension, where you define 
// the "protected" properties and methods of the class

@interface BaseClass ()

// foo is now readwrite
@property (nonatomic, readwrite) NSString *foo;

// bar is visible to implementation of subclasses
@property (nonatomic, readwrite) int bar;

-(void)baz;

@end

#endif

BaseClass.m

// this will import BaseClass.h
// with BaseClass_protected defined,
// so it will also get the protected class extension

#define BaseClass_protected
#import "BaseClass.h"

@implementation BaseClass

-(void)baz {
    self.foo = @"test";
    self.bar = 123;
}

@end

ChildClass.h

// this will import BaseClass.h without the class extension

#import "BaseClass.h"

@interface ChildClass : BaseClass

-(void)test;

@end

ChildClass.m

// this will implicitly import BaseClass.h from ChildClass.h,
// with BaseClass_protected defined,
// so it will also get the protected class extension

#define BaseClass_protected 
#import "ChildClass.h"

@implementation ChildClass

-(void)test {
    self.foo = @"test";
    self.bar = 123;

    [self baz];
}

@end

Когда вы вызываете #import, это в основном копирование-вставкафайл .h туда, куда вы его импортируете.Если у вас есть #ifdef, он будет включать код внутри, только если установлено #define с таким именем.

В вашем файле .h вы не устанавливаете определение, поэтому любые классы, импортирующие это.h не увидит расширение защищенного класса.В файле базового класса и подкласса .m вы используете #define перед использованием #import, чтобы компилятор включал расширение защищенного класса.

0 голосов
/ 12 января 2013

Вы можете использовать такой синтаксис в реализации подкласса.

@interface SuperClass (Internal)

@property (retain, nonatomic) NSString *protectedString;

@end
...