华山论剑之浅谈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(@"世界,你好!");

}

下面是效果图.


内联函数的注意事项


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


总结


关于iOS的宏定义以及内联函数的使用就说到这里,两者说起来各有利弊,但是不得不说的是有了宏定义以及内联函数之后,对开发是一个不少的助力.好了,今天就说到这里了,希望文章对您有所帮助.码字不易,跪求点赞..😄
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,012评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,589评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,819评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,652评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,954评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,381评论 1 210
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,687评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,404评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,082评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,355评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,880评论 1 255
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,249评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,864评论 3 232
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,007评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,760评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,394评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,281评论 2 259

推荐阅读更多精彩内容