且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何在 Objective-C 中使用运行时获取和设置属性值

更新时间:2022-12-04 10:32:08

首先我们必须区分属性和 ivars.如果访问器是显式编码的,或者属性不是 ivar 支持的,则称为存储属性".

First we have to differentiate between properties and ivars. If an accessor is coded explicitly or if the property is not ivar-backed, it is called a "stored property".

A.访问属性

由于属性只是访问器方法的声明,因此访问和获取属性意味着执行访问器方法.

Since a property is simply the declaration of accessor methods, accessing and getting properties means to execute a accessor method.

属性对类的所有实例对象都是通用的.所以,首先得到它:

A property is universal to all instance objects of a class. So, first get it:

Class objectsClass = object_getClass( receiver );

然后你就可以得到财产

objc_property_t property = class_getProperty( objectsClass, [propertyName cStringUsingEncoding:NSASCIIStringEnCoding] );

有了属性,你就可以得到 setter 和 getter 的标识符.

Having the property, you get the identifiers of the setter and getter.

SEL getter;
const char* getterName = property_copyAttributeValue( property, "G" ) 

G 用于 getter,S 用于 setter,如 此处.

G is for getter, S is for setter as described here.

IIRC,如果访问器没有显式设置(setter=..., getter=...),您将得到 nil,因此您必须按照命名约定获取属性名称:

IIRC, you get nil, if the accessor is not set explicitly (setter=…, getter=…), so you have to take the properties name following the naming conventions:

if (getter==NULL)
{
  getter = NSSelectorFromString( propertyName );
}
else
{
  getter = sel_getUid( getterName );
}

使用 setter 会稍微复杂一些,因为您必须在属性名称前加上 set 前缀,并使名称的第一个字符大写.而是简单的字符串处理.

With a setter it is a bit more complicated, because you have to prefix the property's name with set and make the first character of the name uppercased. But simple string processing.

现在我们可以执行访问器了.这对于更复杂的 getter 来说,因为你必须与返回类型不同:integral (id, char, unsigned int, ...),浮点(floatdoublelong double)和结构.您将为每种情况找到一个函数,并应该转换结果.但是对于整型(包括指针),它看起来像这样:

Now we can execute the accessor. This is for getters more complicated, because you have to differ from the return types: integral (id, char, unsigned int, …), floating-point (float, double, long double) and structures. You will find a function for each case and should cast the result. However for integral types (including pointers) it looks like this:

id value = objc_msgSend( receiver, getter );

B.获取 Ivars 值

B. Getting the Ivars Value

如果要获取或设置ivar的值,获取属性的方法也是一样的.在此之后,您读取属性的 V 属性以获取 ivar 的名称.(记住:@synthesize property=differentIvarName).然后你得到了 ivar:

If you want to get or set the value of the ivar, it is the same way to get the property. After this you read the V attribute of the property to get the ivar's name. (Remember: @synthesize property=differentIvarName). Then you get the ivar:

objc_ivar ivar = class_getInstanceVariable( objectsClass, ivarName );

得到它:

id value = object_getIvar( object, ivar );

如果是C类型,就得另辟蹊径,例如

If it is a C type, you have to go a different way, for example

ptrdiff_t offset = ivar_getOffset( ivar );
double value = *((double*)(object+offset));

类似于二传手.

所有内容均在 Safari 中输入,无需重新检查文档.但是它应该是一个深指针.

All is typed in Safari without rechecking the docs. However it should be a deep pointer.

顺便说一句:类型编码描述 这里.

BTW: The type encoding are described here.