【问题标题】:Loop through all object properties at runtime在运行时循环遍历所有对象属性
【发布时间】:2012-02-13 23:05:17
【问题描述】:

我想创建一个 Objective-C 基类,它在运行时对所有(不同类型的)属性执行操作。由于并不总是知道属性的名称和类型,我该如何做这样的事情?

@implementation SomeBaseClass

- (NSString *)checkAllProperties
{
    for (property in properties) {
        // Perform a check on the property
    }
}

编辑:这在自定义 - (NSString *)description: 覆盖中特别有用。

【问题讨论】:

    标签: iphone objective-c ios cocoa-touch


    【解决方案1】:

    为了扩展 mvds 的答案(在我看到他之前就开始写这个),这里有一个小示例程序,它使用 Objective-C 运行时 API 循环并打印关于类中每个属性的信息:

    #import <Foundation/Foundation.h>
    #import <objc/runtime.h>
    
    @interface TestClass : NSObject
    
    @property (nonatomic, retain) NSString *firstName;
    @property (nonatomic, retain) NSString *lastName;
    @property (nonatomic) NSInteger *age;
    
    @end
    
    @implementation TestClass
    
    @synthesize firstName;
    @synthesize lastName;
    @synthesize age;
    
    @end
    
    int main(int argc, char *argv[]) {
        @autoreleasepool {
            unsigned int numberOfProperties = 0;
            objc_property_t *propertyArray = class_copyPropertyList([TestClass class], &numberOfProperties);
    
            for (NSUInteger i = 0; i < numberOfProperties; i++)
            {
                objc_property_t property = propertyArray[i];
                NSString *name = [[NSString alloc] initWithUTF8String:property_getName(property)];
                NSString *attributesString = [[NSString alloc] initWithUTF8String:property_getAttributes(property)];
                NSLog(@"Property %@ attributes: %@", name, attributesString);
            }
            free(propertyArray);
        }
    }
    

    输出:

    房产年龄属性:T^q,Vage
    属性 lastName 属性:T@"NSString",&,N,VlastName
    属性 firstName 属性:T@"NSString",&,N,VfirstName

    请注意,此程序需要在 ARC 开启的情况下编译。

    【讨论】:

    • 一个很好的后续问题是如何动态返回每个值的值......我正在考虑动态创建一个访问器,但在语法上,我仍在尝试解决这个问题。
    • 有几种方法可以做到这一点,但最直接的方法是使用 KVC:id value = [self valueForKey:@"propertyName"]。在同时具有原始(int、float 等)和对象(NSString 等)返回类型的情况下变得有点复杂,但基本前提是可行的。
    • 它是在打开 ARC 的情况下编译的(应该在我的回答中提到)。
    • [self valueForKey:@"propertyName"] 适用于基本类型,自定义类型呢?如何获取自定义类的属性?谢谢!!
    • 我可能不完全明白你在问什么。 [self valueForKey:@"propertyName"] 适用于具有自定义类类型的属性。 -valueForKey:的返回类型是id。
    【解决方案2】:

    使用

    objc_property_t * class_copyPropertyList(Class cls, unsigned int *outCount)
    

    并阅读https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html 了解如何准确执行此操作。

    一些代码可以帮助你:

    #import <objc/runtime.h>
    
    unsigned int count=0;
    objc_property_t *props = class_copyPropertyList([self class],&count);
    for ( int i=0;i<count;i++ )
    {
        const char *name = property_getName(props[i]); 
        NSLog(@"property %d: %s",i,name);
    }
    

    【讨论】:

    • 恒星。接近金属的运行时疯狂的完美资源。
    • 非常感谢,效果很好,如何在运行时将一个对象的属性复制到另一个对象?
    • @PavanSaberjack 使用 valueForKey:setValue:forKey:,您必须注意,如果没有某种形式的转换,char *name 不能用作对象(即 NSString)。
    • @mvds 我遇到了这个问题,当我们在子类中使用该代码时,class_copyPropertyList 没有返回父类属性列表,知道如何解决这个问题吗?
    【解决方案3】:

    向@mvds 添加一些细节:

    unsigned int count=0;
    objc_property_t *props = class_copyPropertyList([self class],&count);
    for ( int i=0;i<count;i++ )
    {
        const char *name = property_getName(props[i]);
        NSString* dataToGet = [NSString swf:@"%s",name];
        @try { // in case of this pair not key value coding-compliant
            id value = [barButton valueForKey:dataToGet];
            NSLog(@"prop %d: %s  %@",i,name, value);
        } @catch (NSException *exception) {
            // NSLog(@"Exception:%@",exception);
        }
        @finally {
            // Display Alternative
        }
    }
    

    请给@mvds 投票。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-01-26
      • 2021-11-20
      • 2016-09-09
      • 2014-12-19
      • 1970-01-01
      • 1970-01-01
      • 2015-12-23
      相关资源
      最近更新 更多