欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

(inline)内联函数在IOS开发中的使用

程序员文章站 2022-03-15 13:37:24
...

今天在阅读YYKit源码(https://github.com/ibireme/YYKit.git)时发现在YYKitMacro.h组件中大量使用的内联函数,例如此文件中的一个函数

(inline)内联函数在IOS开发中的使用
static inline void dispatch_async_on_main_queue(void (^block)()) {
    if (pthread_main_np()) {
        block();
    } else {
        dispatch_async(dispatch_get_main_queue(), block);
    }
}
(inline)内联函数在IOS开发中的使用

使用这个函数

dispatch_async_on_main_queue(^{
        
    });

比如下我们经常使用起来更加简洁:

dispatch_async(dispatch_get_main_queue(), ^{
        
    });

那么再次使用内联函数有什么好处呢?先说什么是内联函数,课本上的定义:内联函数是指用inline关键字修饰的函数。内联函数不是在调用时发生控制转移,而是在编译时将函数体嵌入在每一个调用处。编译时,类似宏替换,使用函数体替换调用处的函数名。C语言原本是不支持inline的,但C++中原生对inline的支持让很多C编译器也为C语言实现了一些支持inline语义的扩展。C99将inline正式放入到标准C语言中,并提供了inline关键字。和C++中的inline一样,C99的inline也是对编译器的一个提示,提示编译器尽量按照内联函数的定义去编译,去除函数调用带来的开销。

C中引入inline关键字的原因: 
inline 关键字用来定义一个类的内联函数,引入它的主要原因是用它替代C中表达式形式的宏定义。


表达式形式的宏定义一例: 
#define ExpressionName(Var1,Var2) (Var1+Var2)*(Var1-Var2)

为什么要取代这种形式呢,且听我道来:

1.首先谈一下在C中使用这种形式宏定义的原因,C语言是一个效率很高的语言,这种宏定义在形式及使用上像一个函数,但它使用预处理器实现,没有了参数压栈,代码生成等一系列的操作,因此,效率很高,这是它在C中被使用的一个主要原因。

2.这种宏定义在形式上类似于一个函数,但在使用它时,仅仅只是做预处理器符号表中的简单替换,因此它不能进行 参数有效性的检测,也就不能享受C编译器严格类型检查的好处,另外它的返回值也不能被强制转换为可转换的合适的类型,这样,它的使用就存在着一系列的 隐患和局限性。

3.在C中引入了类及类的访问控制,这样,如果一个操作或者说一个表达式涉及到类的保护成员或私有成员,你就不可能使用这种宏定义来实现。

4. inline 推出的目的,也正是为了取代这种表达式形式的宏定义,它消除了它的缺点,同时又很好地继承了它的优点。

在使用inline函数要注意
1、你可以使用inline函数完全取代表达式形式的宏定义。

2、内联函数一般只会用在函数内容非常简单的时候,这是因为,内联函数的代码会在任何调用它的地方展开,如果函数太复杂,代码膨胀带来的恶果很可能会大于效率的提高带来的益处。

3、在内联函数内不允许用循环语句和 开关语句。 如果内联函数有这些语句,则编译将该函数视同普通函数那样产生函数调用代码,递归函数(自己调用自己的函数)是不能被用来做内联函数的。内联 函数只适合于只有1~5行的小函数。对一个含有许多语句的大函数,函数调用和返回的开销相对来说微不足道,所以也没有必要用内联函数实现。

既然上面说使用内联函数效率会提高,所以我简单的谢了代码验证下

测试代码如下:

(inline)内联函数在IOS开发中的使用
static inline void add(int x, int y);
int main(int argc, const char * argv[]) {
    clock_t start, finish;
    double  duration;
    start = clock();
    for (int i =0,j =0; i<100000; i++,j++) {
        add(i,j);
    }
    finish = clock();
    duration = (double)(finish - start) / CLOCKS_PER_SEC;
    printf( "%f seconds\n", duration );
    return 0;
}
void add(int x, int y)
{
    int k = x+y;
    printf("%d\n",k);
    
}
(inline)内联函数在IOS开发中的使用

连续运行三次打印的结果是:

0.086523 seconds
0.086504 seconds
0.085425 seconds

然后把内联函数改为普通函数再运行三次

(inline)内联函数在IOS开发中的使用
void add(int x, int y);
int main(int argc, const char * argv[]) {
    clock_t start, finish;
    double  duration;
    start = clock();
    for (int i =0,j =0; i<100000; i++,j++) {
        add(i,j);
    }
    finish = clock();
    duration = (double)(finish - start) / CLOCKS_PER_SEC;
    printf( "%f seconds\n", duration );
    return 0;
}
void add(int x, int y)
{
    int k = x+y;
    printf("%d\n",k);
    
}
(inline)内联函数在IOS开发中的使用

打印结果:

0.085639 seconds
0.086934 seconds
0.085713 seconds

从结果可以看出,在本测试代码中使用内联函数确实能提高运行速度。所以我们以后可以在项目中适度使用内联函数来提高APP性能。

OC中使用inline,主要是为了提高函数调用的效率

使用例子:

static inline NSString * imageURLKeyForState(UIControlState state) {
    return [NSString stringWithFormat:@"image_%lu", (unsigned long)state];
}

我们通常会发现,inline 会有 static来修饰,表示在当前文件中应用,如 static b, 在其它文件中也可以出现static b.不会导致重名的错误.

inline和函数

1.inline函数避免了普通函数的,在汇编时必须调用call的缺点:取消了函数的参数压栈,减少了调用的开销,提高效率.所以执行速度确比一般函数的执行速度要快.
2.集成了宏的优点,使用时直接用代码替换(像宏一样)

inline和宏
1.避免了宏的缺点:需要预编译.因为inline内联函数也是函数,不需要预编译.
2.编译器在调用一个内联函数时,会首先检查它的参数的类型,保证调用正确。然后进行一系列的相关检查,就像对待任何一个真正的函数一样。这样就消除了它的隐患和局限性。
3.可以使用所在类的保护成员及私有成员。

inline 说明
1.内联函数只是我们向编译器提供的申请,编译器不一定采取inline形式调用函数.
2.内联函数不能承载大量的代码.如果内联函数的函数体过大,编译器会自动放弃内联.
3.内联函数内不允许使用循环语句或开关语句
4.内联函数的定义须在调用之前。