内联函数
内联函数是指用inline关键字修饰的函数。内联函数不是在调用时发生控制转移,而是在编译时将函数体嵌入在每一个调用处。编译时,类似宏替换,使用函数体替换调用处的函数名。C语言原本是不支持inline的,但C++中原生对inline的支持让很多C编译器也为C语言实现了一些支持inline语义的扩展。C99将inline正式放入到标准C语言中,并提供了inline关键字。和C++中的inline一样,C99的inline也是对编译器的一个提示,提示编译器尽量按照内联函数的定义去编译,去除函数调用带来的开销。
引入内联函数的主要原因
用它替代C中表达式形式的宏定义
表达式形式的宏定义示例:
#define ExpressionName(Var1,Var2) (Var1+Var2)*(Var1-Var2)
为什么要取代这种形式的宏定义?
- 1.C中使用这种形式宏定义的原因: C语言是一个效率很高的语言,这种宏定义在形式及使用上像一个函数,但它使用预处理器实现,没有了参数压栈,代码生成等一系列的操作,因此,效率很高,这是它在C中被使用的一个主要原因
- 2.存在着一系列的隐患和局限性 这种宏定义在形式上类似于一个函数,但在使用它时,仅仅只是做预处理器符号表中的简单替换,因此它不能进行参数有效性的检测,也就不能享受C编译器严格类型检查的好处,另外它的返回值也不能被强制转换为可转换的合适的类型,这样,它的使用就存在着一系列的隐患和局限性
- 3.类及类的访问控制 在C中引入了类及类的访问控制,这样,如果一个操作或者说一个表达式涉及到类的保护成员或私有成员,你就不可能使用这种宏定义来实现
总结: inline
推出的目的,也正是为了取代这种表达式形式的宏定义,它消除了它的缺点(隐患和局限性),同时又很好地继承了它的优点(效率会提高)
使用inline函数要注意
-
1.你可以使用inline函数完全取代表达式形式的宏定义。
-
2.内联函数一般只会用在函数内容非常简单的时候,这是因为,内联函数的代码会在任何调用它的地方展开,如果函数太复杂,代码膨胀带来的恶果很可能会大于效率的提高带来的益处。
-
3.在内联函数内不允许用循环语句和 开关语句。 如果内联函数有这些语句,则编译将该函数视同普通函数那样产生函数调用代码,递归函数(自己调用自己的函数)是不能被用来做内联函数的。内联 函数只适合于只有1~5行的小函数。对一个含有许多语句的大函数,函数调用和返回的开销相对来说微不足道,所以也没有必要用内联函数实现
Objective-C中使用inline,主要是为了提高函数调用的效率
示例:
static inline NSString * imageURLKeyForState(UIControlState state) {
return [NSString stringWithFormat:@"image_%lu", (unsigned long)state];
}
YYKit
源码YYKitMacro.h
组件中大量使用的内联函数
static inline void dispatch_async_on_main_queue(void (^block)()) {
if (pthread_main_np()) {
block();
} else {
dispatch_async(dispatch_get_main_queue(), block);
}
}
dispatch_async_on_main_queue(^{
...
});
inline
会有 static
来修饰,表示在当前文件中应用
如 static b, 在其它文件中也可以出现static b.不会导致重名的错误
inline
和函数
- 1.inline函数避免了普通函数的,在汇编时必须调用call的缺点:取消了函数的参数压栈,减少了调用的开销,提高效率.所以执行速度确比一般函数的执行速度要快.
- 2.集成了宏的优点,使用时直接用代码替换(像宏一样)
inline
和宏
- 1.避免了宏的缺点:需要预编译.因为inline内联函数也是函数,不需要预编译
- 2.编译器在调用一个内联函数时,会首先检查它的参数的类型,保证调用正确。然后进行一系列的相关检查,就像对待任何一个真正的函数一样。这样就消除了它的隐患和局限性。
- 3.可以使用所在类的保护成员及私有成员。
inline
说明
- 1.内联函数只是我们向编译器提供的申请,编译器不一定采取
inline
形式调用函数. - 2.内联函数不能承载大量的代码.如果内联函数的函数体过大,编译器会自动放弃内联.
- 3.内联函数内不允许使用循环语句或开关语句
- 4.内联函数的定义须在调用之前
Objective-C项目中应用示例
// SwizzlingDefine.h
#ifndef NIM_SwizzlingDefine_h
#define NIM_SwizzlingDefine_h
#import <objc/runtime.h>
static inline void swizzling_exchangeMethod(Class clazz ,SEL originalSelector, SEL swizzledSelector){
Method originalMethod = class_getInstanceMethod(clazz, originalSelector);
Method swizzledMethod = class_getInstanceMethod(clazz, swizzledSelector);
BOOL success = class_addMethod(clazz, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
if (success) {
class_replaceMethod(clazz, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
}
#endif
#ifndef NIM_SwizzlingDefine_h
#define NIM_SwizzlingDefine_h
#endif
作用: 这是C++预编译头文件保护符,保证即使文件被多次包含,头文件也只定义一次.主要目的是防止头文件的重复包含和编译
Swift 没有内联函数一说,默认编译器自动对函数优化
// 调用示例
static func classInitial() {
swizzleMethod
}
private static let swizzleMethod: Void = {
let originalSelector = #selector(UINavigationController.pushViewController(_:animated:))
let swizzledSelector = #selector(hd_pushViewController)
swizzlingForClass(UINavigationController.self, originalSelector: originalSelector, swizzledSelector: swizzledSelector)
}()