OC学习之Runtime之一成员变量和属性

坚持 成长 每日一篇

OC的成员变量和属性

成员变量:就是定义了一个类的全局变量(不直接被外部访问,只能通过方法读或写)
属性:提供了get和set的成员变量。(直接能被外部读写,其实就是能通过.调用法读或写)

由此可知:在OC里面一个属性是和一个成员变量密切相关联的。当我们默认声明一个属性如果没有关联相应的成员变量会默认生成一个以下划线开头+属性名的成员变量。

成员变量操作函数

Ivar是成员变量结构体objc_ivar指针其定义如下

typedef struct objc_ivar *Ivar;

objc_ivar结构体定义如下:

struct objc_ivar {
    char *ivar_name                                          OBJC2_UNAVAILABLE;
    char *ivar_type                                          OBJC2_UNAVAILABLE;
    int ivar_offset                                          OBJC2_UNAVAILABLE;
#ifdef __LP64__
    int space                                                OBJC2_UNAVAILABLE;
#endif
} 

对该结构体的操作函数我们用ivar开头

//获取成员变量名const char * ivar_getName ( Ivar v );  
//获取成员变量类型编码const char * ivar_getTypeEncoding ( Ivar v ); 
//获取成员变量的偏移量

ptrdiff_t ivar_getOffset ( Ivar v ); 

获取类中指定名称实例成员变量的信息

这个函数能够获取父类以上类定义的所有成员变量

Ivar class_getInstanceVariable ( Class cls, const char *name );

获取类成员变量的信息

OC似乎没有类成员变量,这个函数目前还不知道怎么用

Ivar class_getClassVariable ( Class cls, const char *name );

添加成员变量

BOOL class_addIvar ( Class cls, const char *name, size_t size, uint8_t alignment, const char *types );

注意:不管是系统库提供的提供的类,还是我们自定义的类,都无法动态添加成员变量。但如果我们通过运行时来创建一个类的话,又应该如何给它添加成员变量呢?这时我们就可以使用class_addIvar函数了。不过需要注意的是,这个方法只能在objc_allocateClassPair函数与objc_registerClassPair之间调用。

获取整个成员变量列表

Ivar * class_copyIvarList ( Class cls, unsigned int *outCount );

注意:返回的列表不包含父类的成员变量和属性。
例子:

    unsigned int outCount = 0;
    Ivar *vars = class_copyIvarList([self class], &outCount); // 获取到所有的成员变量列表
    NSMutableDictionary *dic = [[NSMutableDictionary alloc] init];
    // 遍历所有的成员变量
    for (int i = 0; i < outCount; i++) {
        Ivar ivar = vars[i]; // 取出第i个位置的成员变量
        const char *propertyName = ivar_getName(ivar); // 获取变量名
        const char *propertyType = ivar_getTypeEncoding(ivar); // 获取变量类型
        NSString *propertyNameString = [NSString stringWithUTF8String:propertyName];
        NSString *propertyTypeString = [NSString stringWithUTF8String:propertyType];
        [dic setValue:propertyTypeString forKey:propertyNameString];
    }

属性操作

objc_property_t
objc_property_t是表示Objective-C声明的属性的类型,其实际是指向objc_property结构体的指针。
注意:这里的objc_property在库中没有找到定义,网上很多资料把objc_property_attribute_t当作objc_property结构体定义。但是objc_property_attribute_t其实是保存属性的一些其他信息如关联的成员变量,类型,引用类型等。

typedef struct objc_property *objc_property_t; 

下面是objc_property_attribute_t定义:

typedef struct {
    const char *name;           /**< The name of the attribute */
    const char *value;          /**< The value of the attribute (usually empty) */
} objc_property_attribute_t;

获取指定的属性

objc_property_t class_getProperty ( Class cls, const char *name );

获取属性列表

这里获取属性的列表是不获取父类的属性,只获取自身属性列表。

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

//属性操作

//cout用于保存取出了多少属性
unsigned int outCount = 0;
objc_property_t * properties = class_copyPropertyList([Person class], &outCount);
for (int i = 0; i < outCount; i++) 
{
     objc_property_t property = properties[i];
     NSLog(@"property's name: %s", property_getName(property));
}

free(properties);//最后必须用free释放

为类添加属性

感觉这个方法好鸡肋,成功添加了属性但是不能用点调用法调用,还是用关联对象比较好用一点。

BOOL class_addProperty ( Class cls, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount );

例子

//给已经有的Person类添加属性littleName。
        objc_property_attribute_t type = { "T", "@\"NSString\"" };//属性类型为NSString
        objc_property_attribute_t ownership = { "C", "copy" }; // C = copy
        objc_property_attribute_t backingivar  = { "V", "_littleName" };//_littleName为Person类的全局变量,这里是让新属性与之关联
        objc_property_attribute_t attrs[] = { type, ownership, backingivar };
        class_addProperty([Person class], "littleName", attrs, 3);
//验证是否添加成功        
        objc_property_t pt =  class_getProperty([Person class], "littleName");
        NSLog(@"property's name: %s", property_getName(pt));
        NSLog(@"property'attribute:%s",property_getAttributes(pt));
        NSLog(@"property'release:%s",property_copyAttributeValue(pt, "C"));
        NSLog(@"property'type:%s",property_copyAttributeValue(pt, "T"));
        NSLog(@"property'value:%s",property_copyAttributeValue(pt, "V"));
//之后我们可以用KVC操作这个属性

替换类的属性

void class_replaceProperty ( Class cls, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount );

获取属性名

const char * property_getName ( objc_property_t property ); 

获取属性特性描述字符串

const char * property_getAttributes ( objc_property_t property ); 

获取属性中指定的特性

char * property_copyAttributeValue ( objc_property_t property, const char *attributeName ); 

实例:

NSLog(@"property'type:%s",property_copyAttributeValue(property, "T"));//"T"表示获取该属性的类型
NSLog(@"property'value:%s",property_copyAttributeValue(property, "V"));//"V"表示获取该属性关联的成员变量

获取属性的特性列表

objc_property_attribute_t * property_copyAttributeList ( objc_property_t property, unsigned int *outCount ); 

注意:
1.property_copyAttributeValue函数,返回的char *在使用完后需要调用free()释放
2. property_copyAttributeList函数,返回值在使用完后需要调用free()释放。
3. 获取属性列表其实是获取的属性名是不带下划线的属性名。所以如果想很好的遍历属性名可以通过获取属性列表函数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 macOS 中,有多种方式进行坐标转换。以下是其中两种常见的方法: 1. 使用坐标转换函数 在 macOS 中,可以使用以下函数将一个坐标点从一个坐标系转换到另一个坐标系: ```objc NSPoint NSConvertPoint(NSPoint aPoint, NSRect fromRect, NSRect toRect); ``` 其中,`aPoint` 是需要转换的坐标点,`fromRect` 是源坐标系(通常是屏幕坐标系),`toRect` 是目标坐标系(通常是视图坐标系)。例如,要将屏幕上的坐标点转换为视图上的坐标点,可以这样写: ```objc NSPoint screenPoint = {100, 100}; // 屏幕坐标系 NSRect viewFrame = [self.view frame]; // 视图坐标系 NSPoint viewPoint = NSConvertPoint(screenPoint, nil, viewFrame); // 转换坐标 ``` 2. 使用坐标转换矩阵 另一种常见的方式是使用坐标转换矩阵。在 macOS 中,可以使用以下方法创建一个坐标转换矩阵: ```objc NSAffineTransform *transform = [NSAffineTransform transform]; [transform scaleXBy:scaleX yBy:scaleY]; [transform rotateByDegrees:rotation]; [transform translateXBy:translateX yBy:translateY]; ``` 其中,`scaleX` 和 `scaleY` 是缩放因子,`rotation` 是旋转角度,`translateX` 和 `translateY` 是平移量。例如,要将屏幕上的坐标点转换为视图上的坐标点,可以这样写: ```objc NSAffineTransform *transform = [NSAffineTransform transform]; [transform translateXBy:-viewFrame.origin.x yBy:-viewFrame.origin.y]; // 将视图坐标系移到原点 [transform concat]; // 应用坐标转换矩阵 NSPoint screenPoint = {100, 100}; // 屏幕坐标系 NSPoint viewPoint = [self.view convertPoint:screenPoint fromView:nil]; // 转换坐标 ``` 这里使用了 `NSView` 类的 `convertPoint:fromView:` 方法,将屏幕上的坐标点转换为视图上的坐标点。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值