【问题标题】:How do I find all the property keys of a KVC compliant Objective-C object?如何找到符合 KVC 的 Objective-C 对象的所有属性键?
【发布时间】:2010-10-21 07:43:03
【问题描述】:

有没有一种方法可以返回符合 NSKeyValueCoding 协议的对象的所有键?

类似于[object getPropertyKeys] 的东西会返回一个由 NSString 对象组成的 NSArray。它适用于任何符合 KVC 的对象。这样的方法存在吗?到目前为止,我在搜索 Apple 文档时没有发现任何内容。

谢谢, G.

【问题讨论】:

    标签: objective-c cocoa properties introspection key-value-observing


    【解决方案1】:
    #import "objc/runtime.h"
    
    unsigned int outCount, i;
    
    objc_property_t *properties = class_copyPropertyList([self class], &outCount);
    for(i = 0; i < outCount; i++) {
        objc_property_t property = properties[i];
        const char *propName = property_getName(property);
        if(propName) {
                const char *propType = getPropertyType(property);
                NSString *propertyName = [NSString stringWithUTF8String:propName];
                NSString *propertyType = [NSString stringWithUTF8String:propType];
        }
    }
    free(properties);
    

    【讨论】:

    • 是的。我已经撤回了我的downmod。顺便说一句,不推荐使用 stringWithCString: - 使用 stringWithUTF8String: 或 stringWithCString:encoding: 代替。
    • 此代码仅收集直接在对象类中声明的属性。要获取对象的所有属性,您还需要遍历超类链并收集这些类的属性。
    • 这个方法是在哪里定义的:getPropertyType(property)
    • 这只会获取使用@property 语法声明的键。通过实现兼容的方法(或方法对)和/或覆盖核心 KVC 处理方法(即 valueForUndefinedKey:、setValue:forUndefinedKey:),一个类可能对其他 keyPaths 是 KVC 兼容的。不幸的是,没有办法明确地获得任意类符合 KVC 的密钥。换句话说,不要依赖这个。
    • @chakrit 他可能定义了一个函数来解析 property_getAttributes 的结果以删除类型名称。您可以查看this page 了解有关此答案和相关代码的更多详细信息。
    【解决方案2】:

    使用class_getPropertyList。这会告诉你对象的所有@properties

    它不一定会列出所有符合 KVC 的属性,因为任何不带参数并返回值的方法都是有效的符合 KVC 的 getter。运行时没有 100% 可靠的方法可以知道哪些行为是属性(例如,-[NSString length]),哪些行为是命令(例如,-[NSFileHandle readDataToEndOfFile])。

    无论如何,您都应该将符合 KVC 的属性声明为 @properties,所以这应该不是什么大问题。

    【讨论】:

      【解决方案3】:

      没有这样的方法,因为 KVO 系统不需要对象/类向它注册它们支持 KVO 的属性。 任何键都可能支持 KVO,唯一知道的方法是从作者的文档中。

      当然,不能保证@property 会支持KVO;很可能编写一个不需要的属性(有时可能是必要的)。因此,在我看来,获取一个类的 @propertys 列表然后假设它们符合 KVO 将是一个危险的选择。

      【讨论】:

      • 你可能有一点,但这对于 CoreData 的 NSManagedObject 派生类非常有用。
      • 好的,但是在Core Data的特定情况下,NSEntityDescription可能会暴露你关心的内容
      • 你说得对,NSEntityDescription 可能更好用。
      【解决方案4】:

      您需要一个 getPropertyType 函数。看到这个帖子:Get an object attributes list in Objective-C

      【讨论】:

        【解决方案5】:

        对于 Swift 旁观者,您可以通过使用 Encodable 功能获得此功能。我将解释如何:

        1. 使您的对象符合Encodable 协议

          class ExampleObj: NSObject, Encodable {
              var prop1: String = ""
              var prop2: String = ""
          }
          
        2. Encodable 创建扩展以提供toDictionary 功能

           public func toDictionary() -> [String: AnyObject]? {
              let encoder = JSONEncoder()
              encoder.outputFormatting = .prettyPrinted
              guard let data =  try? encoder.encode(self),
                    let json = try? JSONSerialization.jsonObject(with: data, options: .init(rawValue: 0)), let jsonDict = json as? [String: AnyObject] else {
                  return nil
              }
              return jsonDict
          }
          
        3. 在您的对象实例上调用 toDictionary 并访问 keys 属性。

          let exampleObj = ExampleObj()
          exampleObj.toDictionary()?.keys
          
        4. 瞧!像这样访问您的属性:

          for k in exampleObj!.keys {
              print(k)
          }
          // Prints "prop1"
          // Prints "prop2"
          

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-03-17
          • 1970-01-01
          • 2015-09-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多