Атрибуты пользовательских свойств в Objective-c - PullRequest
8 голосов
/ 07 февраля 2011

Можно ли создавать атрибуты пользовательских свойств в Objective-C так же, как в VB.NET? Например, в VB.NET вы можете создать атрибут «Browsable» и прочитать его во время выполнения, чтобы определить, следует ли отображать свойство или нет.

Public Class Employee
    <Browsable(True)> _
    Public Property Property1() As String
        Get

        End Get
        Set(ByVal Value As String)

        End Set
    End Property

    <Browsable(False)> _
    Public Property Property2() As String
        Get

        End Get
        Set(ByVal Value As String)

        End Set
    End Property
End Class

Я хотел бы сделать то же самое в Objective-C, даже если это фиксированный атрибут, который может быть установлен только во время компиляции и не может быть изменен вообще.

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

Я знаю стандартные атрибуты Objective-C (только для чтения, неатомные и т. Д.), Но они мне не помогают ... если у вас нет творческого подхода к их использованию. Я также рассмотрел использование атрибутов C с ключевым словом __attribute__(("Insert attribute here")), но у C есть определенные атрибуты, которые служат определенным целям, и я даже не уверен, что вы можете прочитать их во время выполнения. Если я пропустил тот, который может мне помочь, дайте мне знать.

Я пытался использовать typdef. Например:

typdef int serializableInt;
serializableInt myInt;

и используйте property_getAttributes() функцию времени выполнения Objective C, но все, что она говорит мне, это то, что myInt является int. Я предполагаю, что typedef очень похож на макрос в этом случае ... если только я не могу создать переменную типа serializableInt во время выполнения. В любом случае, вот документация Apple о значениях, которые вы получаете из property_getAttributes().

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

Кроме того, это то, что нужно учитывать. Мне действительно не нужно, чтобы атрибут имел значение (ИСТИНА или ЛОЖЬ; 1, 2, 3 или что-то еще), потому что сам атрибут является значением. Если атрибут существует, то сериализуйте; в противном случае пропустите.

Любая помощь приветствуется. Если вы точно знаете, что это невозможно на Objective-C, дайте мне знать. Спасибо.

Ответы [ 5 ]

3 голосов
/ 14 июня 2014

Если вы хотите добавить атрибут для свойства, класса, метода или ivar, вы можете попробовать использовать github.com / libObjCAttr .Его действительно легко использовать, добавьте его через cocoapods, а затем вы можете добавить такой атрибут:

@interface Foo

RF_ATTRIBUTE(YourAttributeClass, property1 = value1)
@property id bar;

@end

И в коде:

YourAttributeClass *attribute = [NSDate RF_attributeForProperty:@"bar" withAttributeType:[YourAttributeClass class]];
// Do whatever you want with attribute, nil if no attribute with specified class
NSLog(@"%@", attribute.property1)
1 голос
/ 26 мая 2013

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

+ (BOOL)automaticallyNotifiesObserversForKey:(NSString*)key { }

Мы могли бы представить свои собственные по аналогии:

+ (BOOL)keyIsBrowsable:(NSString*)key { }

или

+ (NSArray*)serializableProperties { }

Давайте представим, что наш класс называется FOOBar, и мы хотим знать, доступна ли клавиша baz для просмотра. Не создавая FOOBar, мы можем просто сказать:

if ([FOOBar keyIsBrowsable:@"baz"]} { ... }

С помощью этой техники вы можете делать практически все, что угодно, с помощью пользовательских атрибутов. (За исключением таких вещей, как атрибут Serializable, который требует взаимодействия со стороны компилятора, IIRC.) Однако в настраиваемых атрибутах приятно то, что легко сразу определить, что такое метаданные и что присуще фактическому классу. функциональность, но я думаю, что это незначительный выигрыш.

(Конечно, вам, возможно, придется проверить наличие селектора keyIsBrowsable:, точно так же, как вам нужно проверить наличие определенного настраиваемого атрибута. Опять же, здесь настраиваемые атрибуты имеют небольшую опору, так как мы можем указать среде выполнения .NET, чтобы они все были переданы нам.)

1 голос
/ 07 февраля 2011

если я не пропустил вашу точку зрения ...

я бы порекомендовал объявить протокол.затем использование экземпляров объектов objc в качестве переменных в ваших классах objc, которые принимают протокол.

@interface MONProtocol

- (BOOL)isSerializable;
- (BOOL)isBrowsable;

/* ... */

@end

@interface MONInteger : NSObject <MONProtocol>
{
    int value;
}

- (id)initWithInt:(int)anInt;

@end

@interface MONIntegerWithDynamicProperties : NSObject <MONProtocol>
{
    int value;
    BOOL isSerializable;
    BOOL isBrowsable;
}

- (id)initWithInt:(int)anInt isSerializable:(BOOL)isSerializable isBrowsable:(BOOL)isBrowsable;

@end

// finally, a usage
@interface MONObjectWithProperties : NSObject
{
    MONInteger * ivarOne;
    MONIntegerWithDynamicProperties * ivarTwo;
}

@end

, если вы хотите поделиться какой-то реализацией, просто создайте подкласс NSObject и расширьте базовый класс.Затем у вас будет несколько вариантов для написания типов / структур, которые вы хотите представить.

0 голосов
/ 13 июля 2013

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

@interface classTest:NSObject

   @property(strong,nonatomic)NSString *firstName;

   @property(strong,nonatomic)NSString *lastName;

   @property(strong,nonatomic)NSMutableDictionary *metaData;

@end
@implementation classTest

 - (id) init
{

 self = [super init];
 //Add meta data
  metaData=[[NSmutableDictionary alloc]init];

  //
  if( !self ) return nil;
  return self;
 }

@end

, поэтому используйте словарь для добавления и извлечения метаданных ...

я надеюсь, что это поможет ....

0 голосов
/ 06 февраля 2013

Я сталкивался с подобной проблемой при сериализации объектов. Мое решение состоит в том, чтобы добавить @property (nonatomic, readonly) NSArray *serialProperties;, который имеет собственный метод получения, который возвращает имена (как NSString *) свойств этого (под) класса, который должен быть сериализован.

Например:

- (NSArray *)serialProperties {
    return @[@"id", @"lastModified", @"version", @"uid"];
}

Или в подклассе:

- (NSArray *)serialProperties {
    NSMutableArray *sp = [super serialProperties].mutableCopy;
    [sp addObject:@"visibleName"];
    return sp;
}

Вы можете легко получить все свойства и их значения с помощью [self dictionaryWithValuesForKeys:self.serialProperties].

...