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

华山论剑之浅谈iOS的宏定义以及内联函数的使用

程序员文章站 2024-03-21 23:53:10
...
你带着一个故事去听一首歌感觉会不一样,你带着一个故事去找一首歌心情会不一样。
华山论剑之浅谈iOS的宏定义以及内联函数的使用


宏定义的简介


宏定义是C提供的三种预处理功能的其中一种,这三种预处理包括:宏定义、文件包含、条件编译.

1. 不带参数的宏定义:

格式: #define 标识符 字符串

说明:

(1)宏名一般用大写

(2)使用宏可提高程序的通用性和易读性,减少不一致性,减少输入错误和便于修改。例如:数组大小常用宏定义

(3)预处理是在编译之前的处理,而编译工作的任务之一就是语法检查,预处理不做语法检查。

(4)宏定义末尾不加分号;

(5)宏定义写在函数的花括号外边,作用域为其后的程序,通常在文件的最开头。

(6)可以用#undef命令终止宏定义的作用域

(7)宏定义可以嵌套

(8)字符串" "中永远不包含宏

(9)宏定义不分配内存,变量定义分配内存。


2. 带参数的宏定义:

除了一般的字符串替换,还要做参数代换

格式:   #define 宏名(参数表) 字符串

例如:#define S(a,b) a*b

(1)实参如果是表达式容易出问题

(2)宏名和参数的括号间不能有空格

(3)宏替换只作替换,不做计算,不做表达式求解

(4)函数调用在编译后程序运行时进行,并且分配内存。宏替换在编译前进行,不分配内存

(5)宏的哑实结合不存在类型,也没有类型转换。

(6)函数只有一个返回值,利用宏则可以设法得到多个值

(7)宏展开使源程序变长,函数调用不会

(8)宏展开不占运行时间,只占编译时间,函数调用占运行时间(分配内存、保留现场、值传递、返回值)


iOS中常用的宏定义


上面说到宏定义主要分为参数宏和非参数宏,接下来,我们就看一下,在iOS开发过程中我们常用的一些宏定义.

  • 尺寸相关

//主屏幕的宽高
#define KmainHight  [UIScreen mainScreen].bounds.size.height

#define KmainWidth  [UIScreen mainScreen].bounds.size.width

//导航栏高度
#define KnavigationBarHeight (44)

//标签栏高度
#define KtabBarHeight (49)


  • 颜色相关
//普通颜色
#define KmyColor(R,G,B) [UIColor colorWithRed:R/255.0 green:G/255.0 blue:B/255.0 alpha:1.0]

// 随机颜色
#define KrandomColor   [UIColor colorWithRed:arc4random_uniform(256) / 255.0 green:arc4random_uniform(256) / 255.0 blue:arc4random_uniform(256) / 255.0 alpha:1]

  • 语言相关
//获取当前语言
#define KcurrentLanguage ([[NSLocale preferredLanguages] objectAtIndex:0])
  • 系统版本相关
//主要用于判断当前iOS版本号,对其弃用或者未出现的方法进行区别对待
#define KcurrentSystemVersion [[UIDevice currentDevice] systemVersion]  

  • 手机型号相关
//iPhone5
#define IPHONE5 ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(640, 1136), [[UIScreen mainScreen] currentMode].size) : NO)

//iPhone6
#define IPHONE6 ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(750, 1334), [[UIScreen mainScreen] currentMode].size) : NO)

//iPhone6 Plus
#define IPHONE6_Plus ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(1242, 2208), [[UIScreen mainScreen] currentMode].size) : NO)

//Pad
#define KisPad (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)

  • 模拟器相关
/判断是真机还是模拟器  
#if TARGET_OS_IPHONE  

//真机
#endif  
  
#if TARGET_IPHONE_SIMULATOR  

//模拟器

#endif  
  • 国际化相关(国际化相关知识不懂点这里)
#define LocalString(string)     NSLocalizedString(string, nil)

  • 引用相关
//弱引用
#define KweakSelf(type)  __weak typeof(type) weak##type = type;

//强引用
#define KstrongSelf(type)  __strong typeof(type) type = weak##type;
  • 沙盒相关
//获取沙盒主路径
#define KhomePath    NSHomeDirectory()

//获取沙盒 Temp
#define KtempPath NSTemporaryDirectory()

//获取沙盒 Document
#define KdocumentPath    [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]

//获取沙盒 Cache
#define KcachePath [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject]

  • 打印相关
//对象打印
#define KobjectLog(object)  NSLog(@"%@",(object));

//整型数字打印
#define KintNumberLog(number)  NSLog(@"%d",(number));

//float数字打印
#define KfloatNumberLog(number)  NSLog(@"%f",(number));

  • 上线相关

// 自定义NSLog,在debug模式下打印,在release模式下取消一切NSLog(上线时候使用推荐:⭐️⭐️⭐️⭐️⭐️)

#ifdef DEBUG

#define NSLog(FORMAT, ...) fprintf(stderr,"%s:%d\t%s\n",[[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String], __LINE__, [[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String]);

#else

#define NSLog(FORMAT, ...) nil

#endif


内联函数的简介及其使用


当第一次接触内联函数的时候,我认为内敛函数就是宏定义,后来经过度娘的循循教导,我才知道对于内联函数原来是另有乾坤呀.
为什么要使用内联函数呢?其实主要是宏定义虽然简单易懂,但是容易出错,下面我们就举例子说明.
比如下面的这个宏定义,其实很简单,就是比较两个数的大小.

#define Kmax(a, b)  (a) > (b) ? (a) : (b)

然后,我们这样调用

int result = Kmax(i, j) + 2 ; 

其实结果就成了

 result = (i) > (j) ? (i) : (j) + 2 ; 

而我们需要的是

 result = ( (i) > (j) ? (i) : (j) ) + 2 ; 

这样就离我们需要的期望隔着失之毫厘谬以千里....好了,这时候有人就说了,如下改动不就没有任何问题了?但是真的没有问题了吗?

#define Kmax(a, b)   ((a) > (b) ? (a) : (b))

如上的修改的确可以修改上面的问题,但是我们如下使用,还是存在问题的

 result = Kmax(i++, j); 

那么预处理会处理成如下,跟我们的预想的结果还是不一致...

 result = (i++) > (j) ? (i++) : (j); 

看到上面的问题这么多,相信你们的头和我一样是大大的,那么这时候就我们的猪脚--->内联函数来解决问题了,我们先看一下内联函数的结构.

NS_INLINE (函数类型,如void,int,id) 函数名 ( 参数a,参数b,..... ) {
..........(函数实现)..........
}

就拿上面的比较方法,我们可以直接写在PCH文件中.代码如下.(注意:NS_INLINE是内联函数的标志,同时要使用内联函数,需要导入Foundation框架)这样就完美的解决了上面的问题.

#import <Foundation/Foundation.h>

NS_INLINE int max( int a ,int b){
    
    return a>b?a:b;
    
}

下面接着是分享给大家的一个内联函数的应用,一个自定义内联函数弹窗.(注意:因为UIAlertView被弃用的问题,所以会爆一个黄,但是真的很好用,所以就分享一下)

#import <UIKit/UIKit.h>

#import <Foundation/Foundation.h>


NS_INLINE void tipWithMessage(NSString *message){
    
    dispatch_async(dispatch_get_main_queue(), ^{
        
        UIAlertView *alerView = [[UIAlertView alloc] initWithTitle:@"提示" message:message delegate:nil cancelButtonTitle:nil otherButtonTitles:nil, nil];
        
        [alerView show];
        
        [alerView performSelector:@selector(dismissWithClickedButtonIndex:animated:) withObject:@[@0, @1] afterDelay:0.9];
        
    });
    
}


下面对于调用也是非常的简单,如下在-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event 方法中,调用弹窗函数.

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{

    tipWithMessage(@"世界,你好!");

}

下面是效果图.

华山论剑之浅谈iOS的宏定义以及内联函数的使用


内联函数的注意事项


内联是以代码膨胀(复制)为代价,仅仅省去了函数调用的开销,从而提高函数的执行效率。如果执行函数体内代码的时间,相比于函数调用的开销较大,那么效率的收获会很少。另一方面,每一处内联函数的调用都要复制代码,将使程序的总代码量增大,消耗更多的内存空间。以下情况不宜使用内联:
  • (1)如果函数体内的代码比较长,使用内联将导致内存消耗代价较高。
  • (2)如果函数体内出现循环,那么执行函数体内代码的时间要比函数调用的开销大。


总结


关于iOS的宏定义以及内联函数的使用就说到这里,两者说起来各有利弊,但是不得不说的是有了宏定义以及内联函数之后,对开发是一个不少的助力.好了,今天就说到这里了,希望文章对您有所帮助.码字不易,跪求点赞..