zoukankan      html  css  js  c++  java
  • 分析Runtime的属性Property

    一、介绍

    在OC中我们可以给任意的一个类以@property的格式声明属性,当然对于这个属性也会采用某一些属性关键字进行修饰,那么属性的真正的面目是啥样子的呢?其实,runtime源码中可以看到,property是一个结构,如下所示,只不过苹果为这个结构体另外定义了一个结构体指针。

    //属性结构体指针
    typedef struct objc_property *objc_property_t;

    二、函数

    正如我们所知,MJExtension是一个非常流行的json解析框架,其内部对对象的每一个属性进行解析的方式其实就是通过runtime来实现的。runtime源码中提供了属性的相关API函数。通过这些函数,我们可以轻松的得到每一个属性名和类型以及特性,相关函数如下:

    //获取一个属性
    objc_property_t _Nullable class_getProperty(Class _Nullable cls, const char * _Nonnull name);
    
    //添加一个属性
    class_addProperty(Class _Nullable cls, const char * _Nonnull name, const objc_property_attribute_t * _Nullable attributes,unsigned int attributeCount);
    
    //替换一个属性
    class_replaceProperty(Class _Nullable cls, const char * _Nonnull name, const objc_property_attribute_t * _Nullable attributes,unsigned int attributeCount)
    
    //获取属性数组
    objc_property_t _Nonnull * _Nullable class_copyPropertyList(Class _Nullable cls, unsigned int * _Nullable outCount);
    
    //获取属性名称
    const char * _Nonnull property_getName(objc_property_t _Nonnull property) ;
    
    //获取属性描述名称
    const char * _Nullable property_getAttributes(objc_property_t _Nonnull property);
    
    //获取属性描述数组
    objc_property_attribute_t * _Nullable property_copyAttributeList(objc_property_t _Nonnull property,unsigned int * _Nullable outCount);
    
    //通过属性描述的name获取属性描述的value
    property_copyAttributeValue(objc_property_t _Nonnull property,const char * _Nonnull attributeName); 
    
    //属性描述结构体
    typedef struct {
        const char * _Nonnull name;           /**< The name of the attribute */
        const char * _Nonnull value;          /**< The value of the attribute (usually empty) */
    } objc_property_attribute_t;

    三、案例

    了解了基本函数后,现在来上手,获取并打印看看property到底是个啥样,代码如下:

    //定义一个对象,声明各种属性property
    @interface SubObject : NSObject
    @property (nonatomic,   copy) NSString *name;
    @property (nonatomic,   copy) void (^Block)(void);
    @property (nonatomic,   weak) id<NSObject> delegate;
    @property (nonatomic, assign) int      age;
    @property (nonatomic, assign) float    height;
    @property (nonatomic, assign) double   weight;
    @property (nonatomic, strong) NSNumber *num;
    @property (nonatomic, strong) NSDate   *date;
    @property (nonatomic, strong) NSData   *data;
    @property (nonatomic, strong) NSArray  *array;
    @property (nonatomic, strong) NSDictionary *dic;
    @property (nonatomic, strong) MyObject *myObject;
    @end
    //获取属性列表
    unsigned int count;
    objc_property_t *properties = class_copyPropertyList([subObject class], &count);
    for (int i=0; i<count; i++) {
            
          //获取属性
          objc_property_t property = properties[i];
            
          //属性名称
          const char *propertyName = property_getName(property);
          NSLog(@"------propertyName = %s-------",propertyName);
            
          //属性描述名称
          const char * property_attr = property_getAttributes(property);
          NSLog(@"------property_attr = %s-------",property_attr);
            
          //属性类型
          const char *propertyType = property_copyAttributeValue(property, "T");
          NSLog(@"------propertyType = %s-------",propertyType);
            
          //属性变量名称
          const char *property_Value = property_copyAttributeValue(property, "V");
          NSLog(@"------property_Value = %s-------",property_Value);
            
          //属性描述列表
          unsigned int outCount;
          objc_property_attribute_t *attributeList = property_copyAttributeList(property, &outCount);
          for (int j=0; j<outCount; j++) {
              objc_property_attribute_t attribute = attributeList[j];
              NSLog(@"property_attribute_t_name:%s-----property_attribute_t_value:%s",attribute.name,attribute.value);
          }
          NSLog(@"");
    }
    2019-11-10 19:18:10.335830+0800 运行时[4530:256535] ------propertyName = name-------
    2019-11-10 19:18:10.336009+0800 运行时[4530:256535] ------property_attr = T@"NSString",C,N,V_name-------
    2019-11-10 19:18:10.336152+0800 运行时[4530:256535] ------propertyType = @"NSString"-------
    2019-11-10 19:18:10.336261+0800 运行时[4530:256535] ------property_Value = _name-------
    2019-11-10 19:18:10.336405+0800 运行时[4530:256535] property_attribute_t_name:T-----property_attribute_t_value:@"NSString"
    2019-11-10 19:18:10.336532+0800 运行时[4530:256535] property_attribute_t_name:C-----property_attribute_t_value:
    2019-11-10 19:18:10.336648+0800 运行时[4530:256535] property_attribute_t_name:N-----property_attribute_t_value:
    2019-11-10 19:18:10.336770+0800 运行时[4530:256535] property_attribute_t_name:V-----property_attribute_t_value:_name
    2019-11-10 19:18:10.336877+0800 运行时[4530:256535] 
    2019-11-10 19:18:10.336974+0800 运行时[4530:256535] ------propertyName = Block-------
    2019-11-10 19:18:10.337256+0800 运行时[4530:256535] ------property_attr = T@?,C,N,V_Block-------
    2019-11-10 19:18:10.337568+0800 运行时[4530:256535] ------propertyType = @?-------
    2019-11-10 19:18:10.337972+0800 运行时[4530:256535] ------property_Value = _Block-------
    2019-11-10 19:18:10.338296+0800 运行时[4530:256535] property_attribute_t_name:T-----property_attribute_t_value:@?
    2019-11-10 19:18:10.338638+0800 运行时[4530:256535] property_attribute_t_name:C-----property_attribute_t_value:
    2019-11-10 19:18:10.341894+0800 运行时[4530:256535] property_attribute_t_name:N-----property_attribute_t_value:
    2019-11-10 19:18:10.342363+0800 运行时[4530:256535] property_attribute_t_name:V-----property_attribute_t_value:_Block
    2019-11-10 19:18:10.342769+0800 运行时[4530:256535] 
    2019-11-10 19:18:10.343143+0800 运行时[4530:256535] ------propertyName = delegate-------
    2019-11-10 19:18:10.343664+0800 运行时[4530:256535] ------property_attr = T@"<NSObject>",W,N,V_delegate-------
    2019-11-10 19:18:10.343779+0800 运行时[4530:256535] ------propertyType = @"<NSObject>"-------
    2019-11-10 19:18:10.344314+0800 运行时[4530:256535] ------property_Value = _delegate-------
    2019-11-10 19:18:10.344746+0800 运行时[4530:256535] property_attribute_t_name:T-----property_attribute_t_value:@"<NSObject>"
    2019-11-10 19:18:10.345172+0800 运行时[4530:256535] property_attribute_t_name:W-----property_attribute_t_value:
    2019-11-10 19:18:10.345485+0800 运行时[4530:256535] property_attribute_t_name:N-----property_attribute_t_value:
    2019-11-10 19:18:10.345773+0800 运行时[4530:256535] property_attribute_t_name:V-----property_attribute_t_value:_delegate
    2019-11-10 19:18:10.346062+0800 运行时[4530:256535] 
    2019-11-10 19:18:10.346475+0800 运行时[4530:256535] ------propertyName = age-------
    2019-11-10 19:18:10.346859+0800 运行时[4530:256535] ------property_attr = Ti,N,V_age-------
    2019-11-10 19:18:10.347278+0800 运行时[4530:256535] ------propertyType = i-------
    2019-11-10 19:18:10.347784+0800 运行时[4530:256535] ------property_Value = _age-------
    2019-11-10 19:18:10.348131+0800 运行时[4530:256535] property_attribute_t_name:T-----property_attribute_t_value:i
    2019-11-10 19:18:10.348551+0800 运行时[4530:256535] property_attribute_t_name:N-----property_attribute_t_value:
    2019-11-10 19:18:10.348980+0800 运行时[4530:256535] property_attribute_t_name:V-----property_attribute_t_value:_age
    2019-11-10 19:18:10.349373+0800 运行时[4530:256535] 
    2019-11-10 19:18:10.349737+0800 运行时[4530:256535] ------propertyName = height-------
    2019-11-10 19:18:10.350087+0800 运行时[4530:256535] ------property_attr = Tf,N,V_height-------
    2019-11-10 19:18:10.350393+0800 运行时[4530:256535] ------propertyType = f-------
    2019-11-10 19:18:10.350763+0800 运行时[4530:256535] ------property_Value = _height-------
    2019-11-10 19:18:10.351191+0800 运行时[4530:256535] property_attribute_t_name:T-----property_attribute_t_value:f
    2019-11-10 19:18:10.351596+0800 运行时[4530:256535] property_attribute_t_name:N-----property_attribute_t_value:
    2019-11-10 19:18:10.351971+0800 运行时[4530:256535] property_attribute_t_name:V-----property_attribute_t_value:_height
    2019-11-10 19:18:10.352397+0800 运行时[4530:256535] 
    2019-11-10 19:18:10.352694+0800 运行时[4530:256535] ------propertyName = weight-------
    2019-11-10 19:18:10.353102+0800 运行时[4530:256535] ------property_attr = Td,N,V_weight-------
    2019-11-10 19:18:10.353529+0800 运行时[4530:256535] ------propertyType = d-------
    2019-11-10 19:18:10.353791+0800 运行时[4530:256535] ------property_Value = _weight-------
    2019-11-10 19:18:10.354096+0800 运行时[4530:256535] property_attribute_t_name:T-----property_attribute_t_value:d
    2019-11-10 19:18:10.354411+0800 运行时[4530:256535] property_attribute_t_name:N-----property_attribute_t_value:
    2019-11-10 19:18:10.354693+0800 运行时[4530:256535] property_attribute_t_name:V-----property_attribute_t_value:_weight
    2019-11-10 19:18:10.355023+0800 运行时[4530:256535] 
    2019-11-10 19:18:10.355303+0800 运行时[4530:256535] ------propertyName = num-------
    2019-11-10 19:18:10.355567+0800 运行时[4530:256535] ------property_attr = T@"NSNumber",&,N,V_num-------
    2019-11-10 19:18:10.355887+0800 运行时[4530:256535] ------propertyType = @"NSNumber"-------
    2019-11-10 19:18:10.356349+0800 运行时[4530:256535] ------property_Value = _num-------
    2019-11-10 19:18:10.357784+0800 运行时[4530:256535] property_attribute_t_name:T-----property_attribute_t_value:@"NSNumber"
    2019-11-10 19:18:10.358246+0800 运行时[4530:256535] property_attribute_t_name:&-----property_attribute_t_value:
    2019-11-10 19:18:10.358968+0800 运行时[4530:256535] property_attribute_t_name:N-----property_attribute_t_value:
    2019-11-10 19:18:10.359325+0800 运行时[4530:256535] property_attribute_t_name:V-----property_attribute_t_value:_num
    2019-11-10 19:18:10.359998+0800 运行时[4530:256535] 
    2019-11-10 19:18:10.360152+0800 运行时[4530:256535] ------propertyName = date-------
    2019-11-10 19:18:10.360572+0800 运行时[4530:256535] ------property_attr = T@"NSDate",&,N,V_date-------
    2019-11-10 19:18:10.360834+0800 运行时[4530:256535] ------propertyType = @"NSDate"-------
    2019-11-10 19:18:10.361263+0800 运行时[4530:256535] ------property_Value = _date-------
    2019-11-10 19:18:10.361579+0800 运行时[4530:256535] property_attribute_t_name:T-----property_attribute_t_value:@"NSDate"
    2019-11-10 19:18:10.361951+0800 运行时[4530:256535] property_attribute_t_name:&-----property_attribute_t_value:
    2019-11-10 19:18:10.362362+0800 运行时[4530:256535] property_attribute_t_name:N-----property_attribute_t_value:
    2019-11-10 19:18:10.362838+0800 运行时[4530:256535] property_attribute_t_name:V-----property_attribute_t_value:_date
    2019-11-10 19:18:10.363256+0800 运行时[4530:256535] 
    2019-11-10 19:18:10.363500+0800 运行时[4530:256535] ------propertyName = data-------
    2019-11-10 19:18:10.363788+0800 运行时[4530:256535] ------property_attr = T@"NSData",&,N,V_data-------
    2019-11-10 19:18:10.364093+0800 运行时[4530:256535] ------propertyType = @"NSData"-------
    2019-11-10 19:18:10.364430+0800 运行时[4530:256535] ------property_Value = _data-------
    2019-11-10 19:18:10.364925+0800 运行时[4530:256535] property_attribute_t_name:T-----property_attribute_t_value:@"NSData"
    2019-11-10 19:18:10.365110+0800 运行时[4530:256535] property_attribute_t_name:&-----property_attribute_t_value:
    2019-11-10 19:18:10.365525+0800 运行时[4530:256535] property_attribute_t_name:N-----property_attribute_t_value:
    2019-11-10 19:18:10.365928+0800 运行时[4530:256535] property_attribute_t_name:V-----property_attribute_t_value:_data
    2019-11-10 19:18:10.366541+0800 运行时[4530:256535] 
    2019-11-10 19:18:10.366648+0800 运行时[4530:256535] ------propertyName = array-------
    2019-11-10 19:18:10.366929+0800 运行时[4530:256535] ------property_attr = T@"NSArray",&,N,V_array-------
    2019-11-10 19:18:10.367389+0800 运行时[4530:256535] ------propertyType = @"NSArray"-------
    2019-11-10 19:18:10.367686+0800 运行时[4530:256535] ------property_Value = _array-------
    2019-11-10 19:18:10.368112+0800 运行时[4530:256535] property_attribute_t_name:T-----property_attribute_t_value:@"NSArray"
    2019-11-10 19:18:10.368357+0800 运行时[4530:256535] property_attribute_t_name:&-----property_attribute_t_value:
    2019-11-10 19:18:10.368664+0800 运行时[4530:256535] property_attribute_t_name:N-----property_attribute_t_value:
    2019-11-10 19:18:10.368905+0800 运行时[4530:256535] property_attribute_t_name:V-----property_attribute_t_value:_array
    2019-11-10 19:18:10.369409+0800 运行时[4530:256535] 
    2019-11-10 19:18:10.369565+0800 运行时[4530:256535] ------propertyName = dic-------
    2019-11-10 19:18:10.369810+0800 运行时[4530:256535] ------property_attr = T@"NSDictionary",&,N,V_dic-------
    2019-11-10 19:18:10.370092+0800 运行时[4530:256535] ------propertyType = @"NSDictionary"-------
    2019-11-10 19:18:10.370366+0800 运行时[4530:256535] ------property_Value = _dic-------
    2019-11-10 19:18:10.370706+0800 运行时[4530:256535] property_attribute_t_name:T-----property_attribute_t_value:@"NSDictionary"
    2019-11-10 19:18:10.371128+0800 运行时[4530:256535] property_attribute_t_name:&-----property_attribute_t_value:
    2019-11-10 19:18:10.371537+0800 运行时[4530:256535] property_attribute_t_name:N-----property_attribute_t_value:
    2019-11-10 19:18:10.371911+0800 运行时[4530:256535] property_attribute_t_name:V-----property_attribute_t_value:_dic
    2019-11-10 19:18:10.372340+0800 运行时[4530:256535] 
    2019-11-10 19:18:10.372762+0800 运行时[4530:256535] ------propertyName = myObject-------
    2019-11-10 19:18:10.373469+0800 运行时[4530:256535] ------property_attr = T@"MyObject",&,N,V_myObject-------
    2019-11-10 19:18:10.373751+0800 运行时[4530:256535] ------propertyType = @"MyObject"-------
    2019-11-10 19:18:10.374167+0800 运行时[4530:256535] ------property_Value = _myObject-------
    2019-11-10 19:18:10.374515+0800 运行时[4530:256535] property_attribute_t_name:T-----property_attribute_t_value:@"MyObject"
    2019-11-10 19:18:10.374742+0800 运行时[4530:256535] property_attribute_t_name:&-----property_attribute_t_value:
    2019-11-10 19:18:10.375014+0800 运行时[4530:256535] property_attribute_t_name:N-----property_attribute_t_value:
    2019-11-10 19:18:10.375595+0800 运行时[4530:256535] property_attribute_t_name:V-----property_attribute_t_value:_myObject
    2019-11-10 19:18:10.375718+0800 运行时[4530:256535] 

    四、分析

    看到上述打印,发现一些特性,可以获取到属性名称、属性类型,属性原子性、属性引用情况等,这些基本都在属性描述property_attr中,并使用一些特别的字符表示,例如T、@,&,N,V等,每一个属性描述都是以字符“T”开头,以字符“V下划线变量名 V_xxx”结尾 (结尾不固定,对于其他属性)。

    例如属性name的属性描述打印:

    //T:  Type(@encode) 属性类型  
    //@:  对象类型, NSString类型
    //C: Copy  拷贝特性
    //N: nonatomic 非原子性,默认为atomic,atomic为空 
    //V:variable 变量 _name , 使用@property修饰的属性系统默认@synthesize定义下划线变量,_name
    property_attr = T@"NSString",C,N,V_name

    例如属性age的属性描述打印:

    //T:  Type(@encode) 属性类型  
    //i:  基本数据类型, int类型//N: nonatomic 非原子性,默认为atomic,atomic为空 
    //V:variable 变量 _age , 使用@property修饰的属性系统默认@synthesize定义下划线变量,_age
    property_attr = Ti,N,V_age-------

    例如属性myObject的属性描述打印:

    //T:  Type(@encode) 属性类型  
    //@:  对象类型, 自定义类MyObject类型
    //&:  引用特性, 强引用
    //N: nonatomic 非原子性,默认为atomic,atomic为空 
    //V:variable 变量 _myObject-- , 使用@property修饰的属性系统默认@synthesize定义下划线变量,_myObject--
    property_attr = T@"MyObject",&,N,V_myObject-------

    就不一一列举了,基本属性特性大概如下,可能不完整:

    //基本字符表示
    T  是固定开头,表示类型,后跟类型 @、i、f、d、#等
    &  代表强引用
    C  代表copy
    R  代表readOnly属性,readwrite时为空
    W  代表weak,assign为空,默认为assign。
    N  区分的nonatomic和atomic,默认为atomic,atomic为空,’N’代表是nonatomic
    D  @dynamic 动态特性,动态绑定,需要手动生成setter和getter方法
    V_exprice 固定结尾,V代表变量,后面紧跟着的是成员变量名,代表这个property的成员变量名为_exprice。

    属性类型的表示字符特性编码苹果官方给了一套参考:特性编码解析大全

    //编码值   含意
    //c       代表char类型
    //i       代表int类型
    //s       代表short类型
    //l       代表long类型,在64位处理器上也是按照32位处理
    //q       代表long long类型
    //C       代表unsigned char类型
    //I       代表unsigned int类型
    //S       代表unsigned short类型
    //L       代表unsigned long类型
    //Q       代表unsigned long long类型
    //f       代表float类型
    //d       代表double类型
    //B       代表C++中的bool或者C99中的_Bool
    //v       代表void类型
    //*       代表char *类型
    //@       代表对象类型
    //#       代表类对象 (Class)
    //:       代表方法selector (SEL)
    //[array type]  代表array
    //{name=type…}  代表struct结构体
    //(name=type…)  代表union共同体
    //bnum   A bit field of num bits,代表位字段
    //^type  A pointer to type,代表指针类型
    //?      An unknown type (among other things, this code is used for function pointers),代表未知类型,例如block

    四、扩展

    类的属性声明

    //类拥有一个属性
    NS_ASSUME_NONNULL_BEGIN
    @interface MyObject : NSObject
    @property (nonatomic,   copy) NSString *name;
    @end

    1、获取

    -(void)printPropertyWithObj:(MyObject *)myObject{
      unsigned int count;
      objc_property_t *properties = class_copyPropertyList([myObject class], &count);
      for (int i=0; i<count; i++) {
            
        //获取属性
        objc_property_t property = properties[i];
            
        //属性名称
        const char *propertyName = property_getName(property);
        NSLog(@"------propertyName = %s-------",propertyName);
            
        //属性变量
        char *property_Value = property_copyAttributeValue(property, "V");
        NSLog(@"------property_Value = %s-------",property_Value);
            
        //属性类型
        char *property_Type = property_copyAttributeValue(property, "T");
        NSLog(@"------property_Type = %s-------",property_Type);    
      }
    }
    2019-11-10 21:57:24.258232+0800 运行时[6007:365556] ------propertyName = name-------
    2019-11-10 21:57:24.258412+0800 运行时[6007:365556] ------property_Value = _name-------
    2019-11-10 21:57:24.258541+0800 运行时[6007:365556] ------property_Type = @"NSString"-------

    2、添加

    //添加属性
    //* @param cls The class to modify.
    //* @param name The name of the property.
    //* @param attributes An array of property attributes.
    //* @param attributeCount The number of attributes in e attributes.
    //class_addProperty(Classcls, const char *name, const objc_property_attribute_t *attributes,unsigned int attributeCount)
    const char * propertyName = "age";
    objc_property_attribute_t type = { "T", "i" }; //int
    objc_property_attribute_t ownership = { "N" }; //nonatomic
    objc_property_attribute_t variable  = { "V", "_age" }; //_age
    objc_property_attribute_t attrs[]   = { type, ownership, variable };
    BOOL addSuccess = class_addProperty([myObject class], propertyName, attrs, 3);
    if (addSuccess) {
       [self printPropertyWithObj:myObject];
    }
    2019-11-10 22:00:12.120742+0800 运行时[6064:369407] 默认属性如下:
    2019-11-10 22:00:12.120941+0800 运行时[6064:369407] ------propertyName = name-------
    2019-11-10 22:00:12.121073+0800 运行时[6064:369407] ------property_Value = _name-------
    2019-11-10 22:00:12.121199+0800 运行时[6064:369407] ------property_Type = @"NSString"-------
    2019-11-10 22:00:12.121295+0800 运行时[6064:369407] 
    2019-11-10 22:00:12.121405+0800 运行时[6064:369407] 添加属性如下:
    2019-11-10 22:00:12.121617+0800 运行时[6064:369407] ------propertyName = age-------
    2019-11-10 22:00:12.121731+0800 运行时[6064:369407] ------property_Value = _age-------
    2019-11-10 22:00:12.121886+0800 运行时[6064:369407] ------property_Type = i-------
    2019-11-10 22:00:12.122279+0800 运行时[6064:369407] ------propertyName = name-------
    2019-11-10 22:00:12.122780+0800 运行时[6064:369407] ------property_Value = _name-------
    2019-11-10 22:00:12.123222+0800 运行时[6064:369407] ------property_Type = @"NSString"-------

    3、替换

    //替换属性【注意:无法改变属性名称,只是修改生成的下划线变量,_variable】
    //* @param cls The class to modify.
    //* @param name The name of the property.
    //* @param attributes An array of property attributes.
    //* @param attributeCount The number of attributes in e attributes.
    //class_replaceProperty(Class cls, const char *name, const objc_property_attribute_t * _Nullable attributes, unsigned int attributeCount)
    const char * propertyName = "name";
    objc_property_attribute_t type = { "T", "@"NSString"" };//NSString
    objc_property_attribute_t ownership = { "C", "N" }; // copy、nonatomic
    objc_property_attribute_t variable  = { "V", "_newName" }; //_newName
    objc_property_attribute_t attrs[]   = { type, ownership, variable };
    class_replaceProperty([myObject class], propertyName, attrs, 3);
    [self printPropertyWithObj:myObject];
    2019-11-10 22:03:52.448875+0800 运行时[6111:373162] 默认属性如下:
    2019-11-10 22:03:52.450451+0800 运行时[6111:373162] ------propertyName = name-------
    2019-11-10 22:03:52.452714+0800 运行时[6111:373162] ------property_Value = _name-------
    2019-11-10 22:03:52.453001+0800 运行时[6111:373162] ------property_Type = @"NSString"-------
    2019-11-10 22:03:52.453125+0800 运行时[6111:373162] 
    2019-11-10 22:03:52.458433+0800 运行时[6111:373162] 替换属性如下:
    2019-11-10 22:03:52.458658+0800 运行时[6111:373162] ------propertyName = name-------
    2019-11-10 22:03:52.463156+0800 运行时[6111:373162] ------property_Value = _newName-------
    2019-11-10 22:03:52.463973+0800 运行时[6111:373162] ------property_Type = @"NSString"-------
  • 相关阅读:
    Sublime Text 3065
    FBX .NET
    macbook pro的usb串口失效的的处理方法
    CMAKE使用
    Ctrl+Scroll改变所有Editor的缩放比例 (Code::Blocks)
    如何在Mac OSX 10.10上安装GDB
    yum安装指定(特定)版本(旧版本)软件包的方法
    MinGW: TOO MANY SECTIONS issue
    轻量级Image Library
    CodeLite的姿势
  • 原文地址:https://www.cnblogs.com/XYQ-208910/p/11831430.html
Copyright © 2011-2022 走看看