OCRuntime的学习

Objective-C是一门动态的语言,动态就体现在Runtime上面

2016-05-19 | 阅读

关于ObjC Runtime中的 Type Encodings

为了帮助Runtime系统的完成,编译器将每个方法的返回值和参数类型进行编码,成一个字符串,然后与selector的字符串一起组成对一个方法的定义.类型编码也会用在其他地方,可以通过@encode()这个编译器指令宏来来获取类型的type encoding.这个宏中可以放任意的对象类型,向sizeof()一样使用:

char *buf1 = @encode(int **);
char *buf2 = @encode(struct key);
char *buf3 = @encode(Rectangle);

下面是一张表,是常见类型对应的Type Encoding.

  Objective-C type encodings

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)类型返回d,即视为double.

简单举例如下:

NSLog(@"int        : %s", @encode(int));
NSLog(@"float      : %s", @encode(float));
NSLog(@"float *    : %s", @encode(float*));
NSLog(@"char       : %s", @encode(char));
NSLog(@"char *     : %s", @encode(char *));
NSLog(@"BOOL       : %s", @encode(BOOL));
NSLog(@"void       : %s", @encode(void));
NSLog(@"void *     : %s", @encode(void *));

NSLog(@"NSObject * : %s", @encode(ViewController *));
NSLog(@"NSObject   : %s", @encode(ViewController));
NSLog(@"NSArray    : %s",@encode(NSArray<ViewController *>));
NSLog(@"NSArray*   : %s",@encode(NSArray<ViewController *> *));
NSLog(@"[NSObject] : %s", @encode(typeof([ViewController class])));
NSLog(@"NSError ** : %s", @encode(typeof(NSError **)));

int intArray[5] = {1, 2, 3, 4, 5};
NSLog(@"int[]      : %s", @encode(typeof(intArray)));

float floatArray[3] = {0.1f, 0.2f, 0.3f};
NSLog(@"float[]    : %s", @encode(typeof(floatArray)));

typedef struct _struct {
    short a;
    long long b;
    unsigned long long c;
} Struct;
NSLog(@"struct     : %s", @encode(typeof(Struct)));

//输出:
int        : i
float      : f
float *    : ^f
char       : c
char *     : *
BOOL       : c
void       : v
void *     : ^v
NSObject * : @
NSObject   : {NSObject=#}
NSArray    : {NSArray=#}
NSArray*   : @
[NSObject] : #
NSError ** : ^@
int[]      : [5i]
float[]    : [3f]
struct     : {_struct=sqQ}

注意的地方有 :

  • 指针的标准编码是加一个前置的^,但char *有自己的编码*,C的字符串被认为是一个实体,而不是指针
  • BOOLc,i.
  • 直接传入NSObject,将产生#,但是传入NSObject class,产生了一个名为NSObject只有一个类字段的结构体,是isa字段.

对于方法的编码,协议中声明的方法的类型修饰符有:

  Objective-C method encodings

Code

Meaning

r

const

n

in

N

inout

o

out

O

bycopy

R

byref

V

oneway

NSInvocation的用法

NSInvocation中封装了参数和返回值,是runtime中重要的一个部分.

// 初始化只能通过这个函数来初始化,签名只需要与实际调用的参数类型一样就可以了
+ (NSInvocation *)invocationWithMethodSignature:(NSMethodSignature *)sig;

@property (readonly, retain) NSMethodSignature *methodSignature;
// 将参数和返回值retain一遍
- (void)retainArguments;
@property (readonly) BOOL argumentsRetained;
// 设置处理Invocation的对象
@property (nullable, assign) id target;
@property SEL selector;
// 设置和获取返回值.
- (void)getReturnValue:(void *)retLoc;
- (void)setReturnValue:(void *)retLoc;
// 获取参数
- (void)getArgument:(void *)argumentLocation atIndex:(NSInteger)idx;
// 设置参数
- (void)setArgument:(void *)argumentLocation atIndex:(NSInteger)idx;

- (void)invoke;
- (void)invokeWithTarget:(id)target;

这里要注意的地方,是函数参数的起点,数值是2. 首先整体数值是从0开始,但是0上是 target,1上是selector,所以2开始才是参数.