美文网首页iOS开发系统方法解读iOS开发者天堂
华山论剑之浅谈iOS的宏定义以及内联函数的使用

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

作者: 神经骚栋 | 来源:发表于2016-08-22 20:53 被阅读1216次
    你带着一个故事去听一首歌感觉会不一样,你带着一个故事去找一首歌心情会不一样。

    宏定义的简介


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

    相关文章

      网友评论

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

      本文链接:https://www.haomeiwen.com/subject/wsdqjttx.html