ios Objective-C 中的类属性列表
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11774162/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
List of class properties in Objective-C
提问by animal_chin
Is there a way to get an array of class properties of certain kind? For example if i have interface like this
有没有办法获得某种类型的类属性数组?例如,如果我有这样的界面
@interface MyClass : NSObject
@property (strong,nonatomic) UILabel *firstLabel;
@property (strong,nonatomic) UILabel *secondLabel;
@end
can i get the reference to those labels in implementation without knowing their name?
我可以在不知道名称的情况下获得对这些标签的引用吗?
@implementation MyClass
-(NSArray*)getListOfAllLabels
{
?????
}
@end
I know i can do it easily with [NSArray arrayWithObjects:firstLabel,secondLabel,nil]
, but i would like to do it with some kind of class enumeration like for (UILabel* oneLabel in ???[self objects]???)
我知道我可以很容易地做到这一点[NSArray arrayWithObjects:firstLabel,secondLabel,nil]
,但我想用某种类枚举来做到这一点,比如for (UILabel* oneLabel in ???[self objects]???)
回答by
So more precisely, you want dynamic, runtime observaionof the properties, if I got it correctly. Do something like this (implement this method on self, the class you want to introspect):
因此,更准确地说,如果我正确理解,您需要对属性进行动态的、运行时观察。做这样的事情(在 self 上实现这个方法,你想要内省的类):
#import <objc/runtime.h>
- (NSArray *)allPropertyNames
{
unsigned count;
objc_property_t *properties = class_copyPropertyList([self class], &count);
NSMutableArray *rv = [NSMutableArray array];
unsigned i;
for (i = 0; i < count; i++)
{
objc_property_t property = properties[i];
NSString *name = [NSString stringWithUTF8String:property_getName(property)];
[rv addObject:name];
}
free(properties);
return rv;
}
- (void *)pointerOfIvarForPropertyNamed:(NSString *)name
{
objc_property_t property = class_getProperty([self class], [name UTF8String]);
const char *attr = property_getAttributes(property);
const char *ivarName = strchr(attr, 'V') + 1;
Ivar ivar = object_getInstanceVariable(self, ivarName, NULL);
return (char *)self + ivar_getOffset(ivar);
}
Use it like this:
像这样使用它:
SomeType myProperty;
NSArray *properties = [self allPropertyNames];
NSString *firstPropertyName = [properties objectAtIndex:0];
void *propertyIvarAddress = [self getPointerOfIvarForPropertyNamed:firstPropertyName];
myProperty = *(SomeType *)propertyIvarAddress;
// Simpler alternative using KVC:
myProperty = [self valueForKey:firstPropertyName];
Hope this helps.
希望这可以帮助。
回答by serhats
use attributeKeysmethod of NSObject.
使用NSObject 的attributeKeys方法。
for (NSString *key in [self attributeKeys]) {
id attribute = [self valueForKey:key];
if([attribute isKindOfClass:[UILabel class]])
{
//put attribute to your array
}
}
回答by msk
Check out this link. It is an objective c wrapper over objective C runtime.
查看此链接。它是在目标C运行时的客观C包装。
You can use code like below
您可以使用如下代码
uint count;
objc_property_t* properties = class_copyPropertyList(self.class, &count);
NSMutableArray* propertyArray = [NSMutableArray arrayWithCapacity:count];
for (int i = 0; i < count ; i++)
{
const char* propertyName = property_getName(properties[i]);
[propertyArray addObject:[NSString stringWithCString:propertyName encoding:NSUTF8StringEncoding]];
}
free(properties);
回答by Vlad
You must include the runtime headers
您必须包含运行时标头
#import<objc/runtime.h>
uint propertiesCount;
objc_property_t *classPropertiesArray = class_copyPropertyList([self class], &propertiesCount);
free(classPropertiesArray);
回答by jlukanta
The answer by @user529758 won't work with ARC and it won't list the properties of any ancestor classes.
@user529758 的答案不适用于 ARC,也不会列出任何祖先类的属性。
To fix this, you need to traverse up the class hierarchy, and use the ARC-compatible [NSObject valueForKey:]
to get the property values.
要解决此问题,您需要向上遍历类层次结构,并使用 ARC 兼容[NSObject valueForKey:]
来获取属性值。
Person.h:
人.h:
#import <Foundation/Foundation.h>
extern NSMutableArray *propertyNamesOfClass(Class klass);
@interface Person : NSObject
@property (nonatomic) NSString *name;
@end
Person.m:
人名:
#import "Person.h"
#import <objc/runtime.h>
NSMutableArray *propertyNamesOfClass(Class klass) {
unsigned int count;
objc_property_t *properties = class_copyPropertyList(klass, &count);
NSMutableArray *rv = [NSMutableArray array];
for (unsigned int i = 0; i < count; i++)
{
objc_property_t property = properties[i];
NSString *name = [NSString stringWithUTF8String:property_getName(property)];
[rv addObject:name];
}
free(properties);
return rv;
}
@implementation Person
- (NSMutableArray *)allPropertyNames {
NSMutableArray *classes = [NSMutableArray array];
Class currentClass = [self class];
while (currentClass != nil && currentClass != [NSObject class]) {
[classes addObject:currentClass];
currentClass = class_getSuperclass(currentClass);
}
NSMutableArray *names = [NSMutableArray array];
[classes enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(Class currentClass, NSUInteger idx, BOOL *stop) {
[names addObjectsFromArray:propertyNamesOfClass(currentClass)];
}];
return names;
}
- (NSString*)description {
NSMutableArray *keys = [self allPropertyNames];
NSMutableDictionary *properties = [NSMutableDictionary dictionaryWithCapacity:keys.count];
[keys enumerateObjectsUsingBlock:^(NSString *key, NSUInteger idx, BOOL *stop) {
properties[key] = [self valueForKey:key];
}];
NSString *className = NSStringFromClass([self class]);
return [NSString stringWithFormat:@"%@ : %@", className, properties];
}
Student.h:
学生.h:
#import "Person.h"
@interface Student : Person
@property (nonatomic) NSString *studentID;
@end
Student.m:
学生.m:
#import "Student.h"
@implementation Student
@end
main.m:
主.m:
#import <Foundation/Foundation.h>
#import "Student.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
Student *student = [[Student alloc] init];
student.name = @"John Doe";
student.studentID = @"123456789";
NSLog(@"student - %@", student);
}
return 0;
}
回答by palme
The solution of serhats is great unfortunately it doesn't work for iOS (as you mentioned) (and this question is tagged for iOS). A workaround would be to get a NSDictionary representation of the object and then access it normally as key-value pairs. I would recommend a category for NSObject:
serhats 的解决方案很棒,不幸的是它不适用于 iOS(正如你提到的)(并且这个问题被标记为 iOS)。一种解决方法是获取对象的 NSDictionary 表示,然后以键值对的形式正常访问它。我会为 NSObject 推荐一个类别:
Header-File:
头文件:
@interface NSObject (NSDictionaryRepresentation)
/**
Returns an NSDictionary containing the properties of an object that are not nil.
*/
- (NSDictionary *)dictionaryRepresentation;
@end
Implementation-File:
实施文件:
#import "NSObject+NSDictionaryRepresentation.h"
#import <objc/runtime.h>
@implementation NSObject (NSDictionaryRepresentation)
- (NSDictionary *)dictionaryRepresentation {
unsigned int count = 0;
// Get a list of all properties in the class.
objc_property_t *properties = class_copyPropertyList([self class], &count);
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] initWithCapacity:count];
for (int i = 0; i < count; i++) {
NSString *key = [NSString stringWithUTF8String:property_getName(properties[i])];
NSString *value = [self valueForKey:key];
// Only add to the NSDictionary if it's not nil.
if (value)
[dictionary setObject:value forKey:key];
}
free(properties);
return dictionary;
}
@end
Borrowed from this article: http://hesh.am/2013/01/transform-properties-of-an-nsobject-into-an-nsdictionary/
借用这篇文章:http: //hesh.am/2013/01/transform-properties-of-an-nsobject-into-an-nsdictionary/
This way you could do something similar as serhats mentioned:
这样你就可以做一些类似于 serhats 提到的事情:
for (NSString *key in objectDic.allKeys) {
if([objectDic[key] isKindOfClass:[UILabel class]])
{
//put attribute to your array
}
}