OC-類型編碼(TypeEncodings)

類型編碼

為了幫助運(yùn)行時(shí)系統(tǒng),編譯器將每個(gè)方法的返回值和參數(shù)編碼成一個(gè)C字符串,并將這個(gè)字符串和OC的方法選擇器進(jìn)行關(guān)聯(lián)。我們可以用編譯器指令@encode來獲取這個(gè)C字符串。當(dāng)你給一個(gè)指定的類型(這個(gè)類型可以是基本數(shù)據(jù)類型,如int,可以是一個(gè)指針,一個(gè)結(jié)構(gòu)體,類名等,也就是可以作為sizeof()參數(shù)的任何類型),@encode會(huì)返回一個(gè)將這個(gè)類型編碼后的C字符串。總結(jié)為一句話:用一個(gè)C字符串來表示一個(gè)數(shù)據(jù)類型
舉例:

int main(int argc, const char * argv[]) {
  @autoreleasepool {
    char *buf1 = @encode(int);
    char *buf2 = @encode(float);
    char *buf3 = @encode(NSString *);
    NSLog(@"%s",buf1);
    NSLog(@"%s",buf2);
    NSLog(@"%s",buf3);
  }
  return 0;
}

輸出結(jié)果如下:

i
f
@

下面這個(gè)列表列出了一些類型碼及其代表的意義

Code Meaning
c A char
i An int
s A short
l A long
l is treated as a 32-bit quantity on 64-bit programs.
q A long long
C An unsigned char
I An unsigned int
S An unsigned short
L An unsigned long
Q An unsigned long long
f A float
d A double
B A C++ bool or a C99 _Bool
v A void
* A character string (char *)
@ An object (whether statically typed or typed id)
# A class object (Class)
: A method selector (SEL)
[array type] An array
{name=type...} A structure
(name=type...) A 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)

注意:

  • OC 不支持 long double類型,@encode(long double)將會(huì)返回 d ,和double類型的編碼一致。
  • c 數(shù)組,在經(jīng)過編碼后,會(huì)在類型前加上數(shù)組的個(gè)數(shù),如存儲(chǔ)12個(gè)float類型的指針數(shù)組,將會(huì)返回 [12^f]
  • 類對(duì)象會(huì)被當(dāng)作結(jié)構(gòu)體來處理,如@encode(NSObject)將會(huì)返回{NSObject=#}

我們可以將列表中的這些值打印出來

int main(int argc, const char * argv[]) {
  @autoreleasepool {
    NSLog(@"char --> %s",@encode(char));
    NSLog(@"int --> %s",@encode(int));
    NSLog(@"short --> %s",@encode(short));
    NSLog(@"long --> %s",@encode(long));
    NSLog(@"long long --> %s",@encode(long long));
    NSLog(@"unsigned char --> %s",@encode(unsigned char));
    NSLog(@"unsigned int --> %s",@encode(unsigned int));
    NSLog(@"unsigned short --> %s",@encode(unsigned short));
    NSLog(@"unsigned long --> %s",@encode(unsigned long long));
    NSLog(@"float --> %s",@encode(float));
    NSLog(@"bool --> %s",@encode(bool));
    NSLog(@"void --> %s",@encode(void));
    NSLog(@"char * --> %s",@encode(char *));
    NSLog(@"id --> %s",@encode(id));
    NSLog(@"Class --> %s",@encode(Class));
    NSLog(@"SEL --> %s",@encode(SEL));
    int array[] = {1,2,3};
    NSLog(@"int[] --> %s",@encode(typeof(array)));
    typedef struct person{
        char *name;
        int age;
    }Person;
    NSLog(@"struct --> %s",@encode(Person));
    
    typedef union union_type{
        char *name;
        int a;
    }Union;
    NSLog(@"union --> %s",@encode(Union));

    int a = 2;
    int *b = {&a};
    NSLog(@"int[] --> %s",@encode(typeof(b)));

}
  return 0;
}

打印結(jié)果和列表中所列相同,這里不再列出。

應(yīng)用示例

區(qū)分一個(gè)數(shù)組中NSNumber值的具體數(shù)據(jù)類型。

int main(int argc, const char * argv[]) {
  @autoreleasepool {
    NSNumber *num1 = [NSNumber numberWithInt:1];
    NSNumber *num2 = [NSNumber numberWithFloat:1.5];
    NSNumber *num3 = [NSNumber numberWithDouble:1.6];
    NSNumber *num4 = [NSNumber numberWithChar:'A'];
    NSArray *arr = @[num1,num2,num3,num4];
    for (int i=0; i<arr.count; i++) {
        NSNumber *num = arr[i];
        if(0 == strcmp([num objCType], @encode(int))){
            NSLog(@"num%d是int型數(shù)據(jù)",i);
        }else if(0 == strcmp([num objCType], @encode(float))){
            NSLog(@"num%d是float型數(shù)據(jù)",i);
        }else if(0 == strcmp([num objCType], @encode(double))){
            NSLog(@"num%d是double型數(shù)據(jù)",i);
        }else if(0 == strcmp([num objCType], @encode(char))){
            NSLog(@"num%d是char型數(shù)據(jù)",i);
        }else{
            NSLog(@"num%d是其它類型數(shù)據(jù)",i);
        }
    }
  }
  return 0;
}

方法的類型編碼

runtime系統(tǒng)預(yù)備了一些編碼,這些編碼在協(xié)議中聲明方法時(shí)會(huì)用到。編碼列表如下:

Code Meaning
r const
n in
N inout
o out
O bycopy
R byref
V oneway

屬性的類型編碼

當(dāng)我們聲明屬性時(shí),編譯器會(huì)產(chǎn)生一些與封裝的類,類別或協(xié)議相關(guān)聯(lián)的一些元數(shù)據(jù),我們可以獲得這些元數(shù)據(jù)類型作為一個(gè)@encode編譯后的C字符串。總結(jié)為一句話:就是用一個(gè)C字符串來表示屬性的一些描述信息
我們可以通過property_getAttributes函數(shù)去獲得屬性的一個(gè)屬性或者屬性的其他屬性經(jīng)過@encode編碼之后的C字符串。這個(gè)字符串以T開頭,后面緊跟@encode編碼后的C字符串,然后用‘,’分隔,最后以V緊跟實(shí)例變量的返回值結(jié)束。在T和V之間,屬性的屬性用下列字符來描述:

Code Meaning
R The property is read-only (readonly).
C The property is a copy of the value last assigned (copy).
& The property is a reference to the value last assigned (retain).
N The property is non-atomic (nonatomic).
G<name> The property defines a custom getter selector name. The name follows the G (for example, GcustomGetter,).
S<name> The property defines a custom setter selector name. The name follows the S (for example, ScustomSetter:,).
D The property is dynamic (@dynamic).
W The property is a weak reference (__weak).
P The property is eligible for garbage collection.
t<encoding> Specifies the type using old-style encoding.
代碼示例

Person.h

@interface Person : NSObject
@property (nonatomic,copy) NSString *name;
@end

main.m

#import <Foundation/Foundation.h>
#import "Person.h"
#import <objc/runtime.h>

int main(int argc, const char * argv[]) {
  @autoreleasepool {
    Person *p = [[Person alloc] init];
    unsigned int outCount = 0;
    objc_property_t *props = class_copyPropertyList([p class], &outCount);
    for (int i=0 ; i<outCount; i++) {
        objc_property_t prop = props[i];
        NSLog(@"%s",property_getAttributes(prop));
    }
  }
  return 0;
}

輸出結(jié)果:

T@"NSString",C,N,V_name

輸出結(jié)果解釋:

T@"NSString":表示這個(gè)屬性的類型是 NSString 型
C:表示屬性的引用類型是 copy
N:表示 nonatomic
V_name: 表示屬性生成的實(shí)例變量是:_name,我們可以用_name來訪問屬性name的值。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容