【问题标题】:Custom property attributes in Objective-cObjective-c 中的自定义属性属性
【发布时间】:2011-02-07 07:45:58
【问题描述】:

可以像在 VB.NET 中一样在 Objective-C 中创建自定义属性属性吗?例如,在 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 属性(只读、非原子等),但这些对我没有帮助……除非你有创造性的方式来使用它们。我还研究了使用带有 __attribute__(("Insert attribute here")) 关键字的 C 属性,但是 C 具有用于特定目的的特定属性,我什至不确定您是否可以在运行时阅读它们。如果我错过了可以帮助我的人,请告诉我。

我尝试使用typdef。例如:

typdef int serializableInt;
serializableInt myInt;

并使用property_getAttributes() Objective-C 运行时函数,但它告诉我的只是 myInt 是一个 int。我猜 typedef 在这种情况下非常像一个宏......除非我可以在运行时创建一个 serializableInt 类型的变量。无论如何,这是您从property_getAttributes() 获得的值的Apple's documentation

另一个要求是该属性必须与 NSObject 子类以及原始数据类型一起使用。我想到了将黑名单或白名单作为 ivar 添加到类中的想法,它会告诉我要跳过或序列化哪些属性,这基本上是相同的想法。我只是想把黑/白列表移到属性中,这样当你看到一个类的头文件时很容易理解,它在我创建的任何类中都是一致的,而且不容易出错。

另外,这是需要考虑的事情。我真的不需要属性有值(TRUE 或 FALSE;1、2、3 或其他),因为属性本​​身就是值。如果属性存在,则序列化;否则,跳过。

感谢任何帮助。如果您确定这在 Objective-C 上是不可能的,请告诉我。谢谢。

【问题讨论】:

  • 如何创建一个类方法,该方法返回一个包含可序列化实例变量名称的数组?
  • 我想到了这一点,这是一个完美的解决方案。但我的问题是专门关于用属性解决这个问题的。 Objective-C 中是否存在自定义属性?

标签: objective-c ios attributes properties


【解决方案1】:

如果你想给属性、类、方法或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)

【讨论】:

    【解决方案2】:

    除非我错过了你的意思……

    我建议声明一个协议。然后在采用协议的 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 并扩展基类。

    然后,您可以为要表示的类型/结构编写一些变体。

    【讨论】:

    • 我认为你错过了他的观点。他不想说对象是可浏览或可序列化的,而是对象内的属性是可序列化或可浏览的。
    • @ncipollina 没有属性,所以我推荐组合。
    【解决方案3】:

    到目前为止,我看到的其他答案的不足之处在于它们是作为实例方法实现的,即,您需要先拥有一个实例,然后才能查询此元数据。可能存在合适的边缘情况,但关于类的元数据应该作为类方法实现,就像 Apple 所做的那样,例如:

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

    我们可以按照类似的思路来想象我们自己的:

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

    + (NSArray*)serializableProperties { }
    

    假设我们的类名为FOOBar,我们想知道baz 键是否可浏览。无需创建FOOBar,我们可以说:

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

    您几乎可以用这种技术做任何可以用自定义属性来做的事情。 (除了 Serializable 属性,它需要编译器 IIRC 的配合。)不过,自定义属性的好处在于,很容易一眼就区分什么是元数据,什么是该类的实际属性功能,但我认为这是一个很小的收获。

    (当然,您可能必须检查 keyIsBrowsable: 选择器是否存在,就像您必须检查特定自定义属性的存在一样。同样,自定义属性在这里有一点优势,因为我们可以告诉 .NET 运行时将它们全部交给我们。)

    【讨论】:

      【解决方案4】:

      我在序列化对象时遇到了类似的问题。我的解决方案是添加一个 @property (nonatomic, readonly) NSArray *serialProperties;,它有一个自定义 getter,它返回应该序列化的这个(子)类的属性的名称(作为 NSString*)。

      例如:

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

      或者在子类中:

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

      然后您可以通过[self dictionaryWithValuesForKeys:self.serialProperties] 轻松获取所有属性及其值。

      【讨论】:

      • @Bavarious 已经在 cmets 中提出了这个命题——尽管他使用了一种更常见的类方法来解决这个问题。罗伯托明确指出,问题是关于属性的自定义“属性”。
      • 对不起,我一定错过了那条评论。也许我的 sn-ps 仍然可以派上用场;)但是,AFAIK 在objective-c 中没有像“属性”这样的东西。
      • 嗯,属性确实在 objc 运行时具有属性(如只读、原子、动态、弱......)。可以查询这些属性——但它们不可扩展。
      • 那些“属性”实际上只描述了getter/setter是如何实现的。
      【解决方案5】:

      除了 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
      

      所以使用字典来添加和检索元数据...

      希望对你有帮助....

      【讨论】:

        猜你喜欢
        • 2012-02-15
        • 1970-01-01
        • 2017-05-31
        • 2011-05-06
        • 1970-01-01
        • 2020-12-19
        • 1970-01-01
        • 1970-01-01
        • 2020-07-02
        相关资源
        最近更新 更多