extern宏 ios
2016-05-16 22:15:00 weixin_34162228 阅读数 7

####一、宏

#####常见用法:

1).常用的字符串抽成宏(苹果不推荐我们抽成宏,推荐我们使用const常量。)

2).常用的代码抽成宏


#####宏与const的区别

1).编译时刻: 宏:预编译(编译之前处理) const:编译时刻

1).编译检查: 宏:不会检查错误,不会报编译错误,只是简单替换  const:会检查错误

1).宏的好处:可以定义代码

1).宏的坏处:使用大量宏,容易造成编译时间久,每次都需要重新替换,因此常用的字符串通常使用const修饰

#####tips:

以 #开头的 是编译之前处理

很多Blog都说使用宏,会消耗很多内存,我这验证并不会生成很多内存,宏定义的是常量,常量都放在常量区,只会生成一份内存。

####二、const:常量,修饰符

######1.理解:

1).const仅仅用来修饰右边的变量(基本数据变量p,指针变量*p)

2).被const修饰的"变量"是只读的(不可修改)。

🍐(例子)

const int a = 10;

int const a = 10;

const int *a;

int * const a;

int const *const a ;

前两个是一样,即:a是一个常整型数,a的值不可修改;  a=20; => 会报错

第三个意味着a是一个指向常整型数的指针(const修饰指针变量访问的内存空间,即:整型数,不可修改的,但指针可以);a = 20;=>不会报错;  *a = &a; => 会报错 ;

第四个意思a是一个指向整型数的常指针(也就是说,指针指向的整型数是可以修改的,但指针是不可修改的)a = 20;=>会报错;  *a = &a; => 不会报错  ;  

最后一个意味着a是一个指向常整型数的常指针(也就是说,指针指向的整型数是不可修改的,同时指针也是不可修改的)a = 20;=>会报错;  *a = &a; => 会报错  ;

######2.使用场景:

1).当一个方法参数只读

~~~

// 当一个方法的参数,只读.

- (void)test:(NSString * const)name

{}

// 指针只读,不能通过指针修改值

- (void)test1:(int const *)a{

//    *a = 10;

}

~~~

2).定义只读全局变量(经常使用)

######3.总结

1)欲阻止一个变量被改变,可以使用const关键字。在定义该const变量时,通常需要对它进行初始化,因为以后就没有机会再去改变它了;

2)对指针来说,可以指定指针本身为const,也可以指定指针所指的数据为const,或二者同时指定为const;(3)在一个函数声明中,const可以修饰形参,表明它是一个输入参数,在函数内部不能改变其值;

4)对于类的成员函数,若指定其为const类型,则表明其是一个常函数,不能修改类的成员变量;

####三、static:静态变量

1.理解:

变量的内存只被分配一次。从面向对象的角度触发,当需要一个数据对象为整类而非某个对象服务,同时有力求不破坏类的封装性,既要求此成员隐藏在类的内部,有要求对外不可见的时候,就可以使用static。

2.优点:

1)节省内存。静态变量只存储一处,但供所有对象使用。

2)它的值是可以更新的。

3)可提高时间效率。只要某个对象对静态变量更新一次,所有的对象都能访问更新后的值。

3.作用:

1).在方法体内,声明为静态的变量(局部静态变量),其作用域被限制在本方法内,而它的生命周期却为整个整个源程序。当多次调用一个方法且需要保留变量的值时,可采用局部静态变量(例:cellForRow中,cell重用的标识 ),虽然用全局变量也可以达到上述目的,但全局变量有时会造成意外的副作用,故而仍以采用局部静态变量为宜。

2).在源文件内(但在方法体外),全局静态变量,其作用域:在源文件内所用方法皆可访问,但不能被源文件外其它函数访问,近似一个本地的全局变量。

3).static也可用于声明方法,在源文件内,用static声明的方法只可被这一源文件内的其它方法调用。也就是说,这个方法的作用域被限制在声明它的源文件内使用。

4.总结:

局部变量和局部静态变量区别在于它的生命周期。全局变量和全局静态变量的区别在于作用域,后者限制了它的使用范围;当然变量和静态变量的不同之处在于后者的内存只被分配一次。    

开发使用场景:在一个文件中经常使用的只读字符串常量,可以使用static与const组合    需要注意的是: 静态变量需要酌情使用,滥用会导致占用过多内存。

附: 无论是.h或.m文件中,static 写在interface外面编译是没有错误的,但写在interface里面会直接报错。

//example.m

#import "example.h"

static int count = 10;

@implementation Example

+(int)count{

returncount;

}

@end

上面的例子中可以通过[Example count]对静态变量count进行访问,无须创建实例。



####四、extern:全局变量,也称之为外部变量

1.理解:

是在方法外部定义的变量,作用域是整个源程序。另外如果全局变量和局部变量重名,则在局部变量作用域内,全局变量被屏蔽,不起作用。

2.使用:

在.h文件中:声明全局变量,例:

extern const CGFloat height;

extern const CGFloat duration;

在.m文件中:定义.h中声明的全局变量:

const CGFloat height = 64.0;

const CGFloat duration = 0.25;

注意:不可直接在.h文件中直接定义变量即:

extern const CGFloat height=64.0;

因为如果在.h里面定义,当全局变量被多个文件使用时,需要多次包含.h头文件,这样会导致重复定义这个全局变量

3.总结

开发中使用场景:在多个文件中经常使用的同一个只读字符串常量,可以使用extern与const组合,当然编程时候需酌情使用全局变量。

####最后

以上内容参考自“小码哥”的一些资料,以及网上技术博客,如有不足之处望指点

2016-03-31 17:27:00 u013166985 阅读数 226

参考:http://www.yyxt.com/tutorial/10576.html
一、const与宏的区别
常用的字符串常量,一般抽成宏,但是苹果官方不推荐使用宏,而是推荐使用const常量。

编译时刻:宏是预编译(编译之前处理),const是编译阶段。
编译检查:宏不做检查,不会报编译错误,只是替换,const会编译检查,会报编译错误。
宏的好处:宏能定义一些函数,方法。 const不能。
宏的坏处:使用大量宏,容易造成编译时间久,每次都需要重新替换。
注意:很多Blog都说使用宏,会消耗很多内存,我这验证并不会生成很多内存,宏定义的是常量,常量都放在常量区,只会生成一份内存。

1、宏的用法:

#define MACRO_STR @"this is macro string"//定义宏
NSString *macroStr1 = MACRO_STR;         //使用宏
NSString *macroStr2 = MACRO_STR;         //使用宏

对比macroStr1和macroStr2的地址值,发现地址值是一致的。

2、const的用法:
(1)、对于基本数据类型,一下两种做法均使其作为常量

int const aa = 10;
const int bb = 10;
aa = 11;//报错
bb = 11;//报错

aa、bb均为只读常量

(2)、对于指针类型

// *str1不能被修改,str1 能被修改
// *str1为常量,str1为变量
const NSString *str1 = @"const str1";

// *str2不能被修改,str2能被修改
// *str2为常量,str2为变量
NSString const *str2 = @"const str2";

// str3不能被修改,*str3能被修改
// str3为常量,*str3为变量
NSString *const str3 = @"const str3";

//总结:str1、str2没区别;在const右边不能修改

继续举栗子:

int * const i = 1; // *i是变量,i是常量
int const *j = 1;  // *j是变量,j是常量

3、const的使用场景:
a.定义一个方法,方法参数是地址,只能通过地址读取值,不能通过地址修改值。

实现:

-(void)method1:(int const *)a{
    int i = *a;
    NSLog(@"%d",i);//打印值
}

调用:

int iii = 10;
[self method1:&iii];//结果:10

b.定义一个方法,方法参数是地址,里面不能修改参数的地址,只能修改参数的值。

实现:

-(void)method2:(int * const)a{
    *a = 20;
    NSLog(@"%d",*a);//打印结果
}

调用:

int cc = 30;
[self method2:&cc];//结果:20

二、static和extern的简单使用:
1、static:
修饰局部变量
1.延长局部变量的生命周期,程序结束才会销毁。
2.局部变量只会生成一份内存,只会初始化一次。
3.改变局部变量的作用域。

修饰全局变量
1.只能在本文件中访问,修改全局变量的作用域,生命周期不会改
2.避免重复定义全局变量

2、extern
用于获取全局变量(包括全局静态变量)的值,不能用于定义变量。
工作原理:现在当前文件查找有没有全局变量,没有找到,才回去其他文件查找。

三、static与const联合使用

static与const作用:声明一个只读的静态变量。

开发使用场景:在一个文件中经常使用的字符串常量,可以使用static与const组合

static const int a = 20; 

开发中使用这种方式代替宏,把一个经常使用的字符串常量,定义成静态全局只读变量。如作为key值,表示只读,不允许修改。

四、extern与const联合使用

开发中使用场景:在多个文件中经常使用的同一个字符串常量,可以使用extern与const组合。

原因:

static与const组合:在每个文件都需要定义一份静态全局变量。

extern与const组合:只需要定义一份全局变量,多个文件共享。

全局常量正规写法:开发中便于管理所有的全局变量,通常搞一个GlobeConst文件,里面专门定义全局变量,统一管理,要不然项目文件多不好找。

extern NSString * const nameKey = @"name";
2019-02-12 16:03:00 weixin_34301132 阅读数 11

一、Const:限制类型,仅仅用来修饰右边的变量,被const修饰的变量是只读的;

    使用场景一:修饰群居变量,目的是:使外界无法修改变量,保持只读,提高预编译的速度和时间;

    使用场景二:修饰方法中的参数,参数不可被修改;

二、宏的简单使用

    宏是一种规则或者模式,或称语法替换,这种替换在预编译时进行,称作宏展开,如果代码中大量的使用宏会使预编译的时间变长,但是宏只会在内存中Copy一份,并且为常量,会当在常量区,然后全局替换,宏一般分为对象宏和函数宏。

三、static简单使用

修饰局部变量,延长生命周期,跟整个应用程序有关,程序结束才会销毁,但是分配内存地址只会一次。

修饰全局变量,作用域会修改,也就是只能在当前文件下使用;

四、extern简单使用

声明外部全局变量(只用于声明,不能用于定义),我们在类中声明在其他类中使用时只需要声明下就好了。

工作原理:先会去当前文件下查找有没有对应的全局变量,如果没有,才会去其他文件查找。

2019-02-05 23:54:00 weixin_33878457 阅读数 3

一、const 的介绍和基本使用以及使用场景

  • 1.1、const 简介:经常使用的字符串常量,一般是抽成宏,但是苹果不推荐我们抽成宏,推荐我们使用const常量。

  • 1.2、const 作用:限制类型

    • const 仅仅用来修饰右边的变量(基本数据变量p,指针变量*p),被const修饰的变量是只读的。如下
      • const 用法一 (修饰基本变量p)
        不使用const修饰基本变量,允许修改值

        int a = 10;
        a = 12;
        NSLog(@"a=%d",a);
        打印结果:a=12
        

        使用const修饰基本变量

        //这两种写法是一样的,const只修饰右边的基本变量 b
        const int b = 5; // b:只读变量
        int const b = 5; // b:只读变量
        // 由于b是只读的,b无法被修改,入下代码会报错
        b = 3 // 报错,b无法修改
        
      • const 用法二 (修饰指针变量 *p,带*的变量,就是 指针变量)
        不使用const修饰指针变量

        // 修饰指针变量 *p,带 * 的变量,就是指针变量
        // 定义一个指向int类型的指针变量,指向a的地址
        a = 12;
        int *p = &a;
        int c = 7;
        p = &c;
        NSLog(@"p=%d",*p);
        打印结果:p=7
        
        // 由于 p 没有被修饰,它访问 内存空间的值 和 指向的地址 都可以被修改允许修改
        *p = 11;
        NSLog(@"p=%d",p);
        打印结果:p=11
        

        使用 const 修饰指针变量,const 修饰指针变量访问的内存空间,修饰的是右边东西,如下 8 种情况来分析

        // 1、2、4 的效果一样 都是修饰 const右边的 *q,3修饰的是变量 q ,切记 const修饰的是右边的
        int const *q = 7;   // 1
        const int *q = 7;   // 2
        int * const q = 7;  // 3
        const int *q = 7;   // 4
        // 首先下面的 q 都被修饰,也就是q不能被赋值,然后 * const q 又被 const 修饰
        int const * const q = 7;  // 5
        const int * const q = 7;  // 6
        const int * const q = 7;  // 7
        const int * const q = 7;  // 8
        

        提示:

        • 1、2、4 的效果一样 都是修饰 const右边的 *q3 修饰的是变量 q ,切记 const 修饰的是右边的
        • 首先下面的 q 都被修饰,也就是 q 不能被赋值,然后 * const q 又被 const 修饰
  • 1.3、const 的使用场景(场景一用的居多)

    • 场景一:修饰全局变量,目的是:使外界无法修改变量,保持只读,提高预编译的速度和时间(苹果建议使用 const),如下:

      // 设置基础的url,这样来保证base_url的不变(封装请求的类)
      NSString * const base_url =  @"http://www.baodu.com/";
      
    • 场景二:修饰方法中的参数,如下

      -(void)constTest2{
           [self test:@"你好!"];
           int p = 1;
           [self test1:&p];
           [self test2:2];
      }
      
      // 当一个方法的参数,只读.
      -(void)test:(NSString * const)string{
           // 这句代码是报错的,被 const 修饰过后,string 是无法被修改的
           string = @"234";
      }
      // 指针只读,不能通过指针修改值
      - (void)test1:(int const *)a{
           //  *a = 11;
      }
      
      // 基本数据类型只读
      - (void)test2:(int const)a{
      
      }
      

二、宏 的简单使用

  • 2.1、基本概念:宏是一种批量处理的称谓。一般说来,宏是一种规则或模式,或称语法替换 ,用于说明某一特定输入(通常是字符串)如何根据预定义的规则转换成对应的输出(通常也是字符串)。这种替换在预编译时进行,称作宏展开。编译器会在编译前扫描代码,如果遇到我们已经定义好的宏那么就会进行代码替换,宏只会在内存中copy一份,然后全局替换,宏一般分为对象宏和函数宏,推荐博客

  • 2.2、宏的弊端:如果代码中大量的使用宏会使预编译时间变长。

  • 2.3、常用宏举例如下

    /** 1、屏幕的宽高 */
    #define JK_SCREEN_WIDTH  [UIScreen mainScreen].bounds.size.width
    #define JK_SCREEN_HEIGHT  [UIScreen mainScreen].bounds.size.height
    /** 2、判断是不是苹果手机 */
    #define JKIs_Iphone (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
    
  • 2.4、const与宏的区别?

    答:1.编译时刻 宏:预编译 const:编译;2.编译检查 宏没有编译检查,const有编译检查;3.宏的好处 定义函数,方法 const不可以;4.宏的坏处 大量使用宏,会导致预编译时间过长

    提示:

    • 预编译:在打开项目的时候上面会有一个加载项目的进度条就是预编译
    • 编译:command+R和command+B都是编译
    • 网上的误区:大量使用宏,会导致内存暴增(定义一个字符串的宏,赋值给多个变量,打印其内存地址,经过测试:宏定义的是常量,常量都放在常量区,只会生成一份内存,故网上说的都是不对的),如下图
      1728484-88fb433e245dfde1.jpeg
      网上误区

三、static 简单使用

  • 3.1、修饰局部变量

    • <1>、被static修饰局部变量,延长生命周期,跟整个应用程序有关,程序结束才会销毁,如下:在一个类的里面打印下面的方法,只要程序不销毁, a 的值就不会被销毁,会一直保持最后一次给 a 赋的值

      -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
      
            static int a = 0;
            ++a;
            NSLog(@"a=%d",a);
      }
      
    • <2>、被 static 修饰局部变量,只会分配一次内存,如下:从打印结果我们可以看到,a 的内存地址不会再变

      static int a = 0;
      ++a;
      NSLog(@"a = %d a的内存地址=%p",a,&a);
      部分打印结果:
      a = 1   a的内存地址=0x10e758160
      a = 2   a的内存地址=0x10e758160
      a = 3   a的内存地址=0x10e758160
      a = 4   a的内存地址=0x10e758160
      

      提示:被static修饰局部变量什么时候分配内存?程序一运行就会给static修饰变量分配内存

  • 3.2、修饰全局变量,被static修饰全局变量,作用域会修改,也就是只能在当前文件下使用

    #import "ViewController.h"
    
    static int b = 20;
    
    @interface ViewController ()
    
    @end
    
    @implementation TestViewController
    
    - (void)viewDidLoad {
         [super viewDidLoad];
    
        self.view.backgroundColor = [UIColor purpleColor];;
    }
    @end
    

四、extern 简单使用

  • 4.1、声明外部全局变量(只能用于声明,不能用于定义),举例如下:我们在类里面定义的全局变量,在其他的类里面使用的时候只要声明一下就好

    #import "ViewController.h"
    int x = 20;
    
    @interface ViewController ()
    
    @end
    
    @implementation TestViewController
    
    - (void)viewDidLoad {
          [super viewDidLoad];
    
          self.view.backgroundColor = [UIColor purpleColor];;
    }
    @end
    

    在其他类里面使用一,如下:声明一下即可

    #import "TestViewController.h"
    
    @interface TestViewController ()
    
    @end
    
    @implementation TestViewController
    
    - (void)viewDidLoad {
          [super viewDidLoad];
    
          self.view.backgroundColor = [UIColor purpleColor];;
    }
    
    extern int x;
    -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    
         NSLog(@"x的值是:%d",x);
         // 打印结果: x的值是:20
    }
    @end
    

    在其他类里面使用二,如下:在ViewController类的.h里面声明一下即可,如下:

    #import <UIKit/UIKit.h>
    
    @interface ViewController : UIViewController
    
    extern int x;
    
    @end
    
  • 4.2、extern工作原理:先会去当前文件下查找有没有对应全局变量,如果没有,才会去其他文件查找

五、static 与 const 联合使用

  • 5.1、回顾一下 static 与 const
    const:修饰全局变量
    static:修饰全局变量,修改作用域

  • 5.2、static 与 const 联合使用
    如果我们想这个 BASE_URL无法被其他类使用,那么我们就在前面加上 static 因为 static 修饰全局变量,修改作用域,只能在 UrlTest里面使用,再其他类里面使用是不可以的,切记:这个 BASE_URL 是在 .m 里面定义的

    #import "UrlTest.h"
    
    static NSString * const BASE_URL  =  @"http://www.baodu.com/";
    
    @implementation UrlTest
    
    @end
    

六、extern 与 const 联合使用

  • 6.1、开发中使用场景:在多个文件中经常使用的同一个字符串常量,可以使用extern与const组合。原因入下:

    • static与const组合:在每个文件都需要定义一份静态全局变量。
    • extern与const组合:只需要定义一份全局变量,多个文件共享。

    提示:开发中便于管理所有的全局变量,通常搞一个Global文件,里面专门定义全局变量,统一管理,要不然项目文件太多不好找。

  • 6.2、extern的基本使用 :当我们在一个防止一个变量被修改的时候,我们在前面加上 const,如下,仅仅是 BASE_URL无法被修改,在自己的.h文件里面 extern 声明一下即可,在其他类里面通过 导入 .h 文件,还是可以使用的 BASE_URL

    • UrlTest的.h文件 ( 声明 BASE_URL )

      #import "UrlTest.h"
      // 声明  BASE_URL
      extern NSString * const BASE_URL;
      
      @implementation UrlTest
      
      @end
      
    • UrlTest的.m文件

      #import "UrlTest.h"
      
      NSString * const BASE_URL  =  @"http://www.baodu.com/";
      
      @implementation UrlTest
      
      @end
      

      提示:定义全局的东西,遵循规定,顶一个以全局的文件来管理全局变量,以避免全局变量重复定义

  • 6.3、extern 的高级使用 (模仿 YYKIT 的使用 ),其实它只是把苹果的宏拿过来改改名字,看起来很牛逼,我们也可以牛逼一下,如下:

    • 苹果的定义:

      #ifdef __cplusplus
      #define UIKIT_EXTERN     extern "C" __attribute__((visibility ("default")))
      #else
      #define UIKIT_EXTERN         extern __attribute__((visibility ("default")))
      #endif
      
    • 我们只需要把 UIKIT_EXTERN 改为 JKKIT_EXTERN,那以后我们就可以使用我们自己定义的

      #ifdef __cplusplus
      #define JKKIT_EXTERN        extern "C" __attribute__((visibility ("default")))
      #else
      #define JKKIT_EXTERN            extern __attribute__((visibility ("default")))
      #endif
      
    • 苹果和我们自己定义的使用如下

      #import <Foundation/Foundation.h>
      #import <UIKit/UIKit.h>
      
      #ifdef __cplusplus
      #define JKKIT_EXTERN        extern "C" __attribute__((visibility ("default")))
      #else
      #define JKKIT_EXTERN            extern __attribute__((visibility ("default")))
      #endif
      
      // 使用自己定义的
      JKKIT_EXTERN NSString * const BASE_URL;
      // 使用苹果定义的 UIKIT_EXTERN
      // UIKIT_EXTERN NSString * const BASE_URL;
      
      NS_ASSUME_NONNULL_BEGIN
      
      @interface UrlTest : NSObject
      
      @end
      
      NS_ASSUME_NONNULL_END
      

转载于:https://www.jianshu.com/p/44615b9e433d

2019-02-05 23:54:00 weixin_34375251 阅读数 3

一、const 的介绍和基本使用以及使用场景

  • 1.1、const 简介:经常使用的字符串常量,一般是抽成宏,但是苹果不推荐我们抽成宏,推荐我们使用const常量。

  • 1.2、const 作用:限制类型

    • const 仅仅用来修饰右边的变量(基本数据变量p,指针变量*p),被const修饰的变量是只读的。如下
      • const 用法一 (修饰基本变量p)
        不使用const修饰基本变量,允许修改值

        int a = 10;
        a = 12;
        NSLog(@"a=%d",a);
        打印结果:a=12
        

        使用const修饰基本变量

        //这两种写法是一样的,const只修饰右边的基本变量 b
        const int b = 5; // b:只读变量
        int const b = 5; // b:只读变量
        // 由于b是只读的,b无法被修改,入下代码会报错
        b = 3 // 报错,b无法修改
        
      • const 用法二 (修饰指针变量 *p,带*的变量,就是 指针变量)
        不使用const修饰指针变量

        // 修饰指针变量 *p,带 * 的变量,就是指针变量
        // 定义一个指向int类型的指针变量,指向a的地址
        a = 12;
        int *p = &a;
        int c = 7;
        p = &c;
        NSLog(@"p=%d",*p);
        打印结果:p=7
        
        // 由于 p 没有被修饰,它访问 内存空间的值 和 指向的地址 都可以被修改允许修改
        *p = 11;
        NSLog(@"p=%d",p);
        打印结果:p=11
        

        使用 const 修饰指针变量,const 修饰指针变量访问的内存空间,修饰的是右边东西,如下 8 种情况来分析

        // 1、2、4 的效果一样 都是修饰 const右边的 *q,3修饰的是变量 q ,切记 const修饰的是右边的
        int const *q = 7;   // 1
        const int *q = 7;   // 2
        int * const q = 7;  // 3
        const int *q = 7;   // 4
        // 首先下面的 q 都被修饰,也就是q不能被赋值,然后 * const q 又被 const 修饰
        int const * const q = 7;  // 5
        const int * const q = 7;  // 6
        const int * const q = 7;  // 7
        const int * const q = 7;  // 8
        

        提示:

        • 1、2、4 的效果一样 都是修饰 const右边的 *q3 修饰的是变量 q ,切记 const 修饰的是右边的
        • 首先下面的 q 都被修饰,也就是 q 不能被赋值,然后 * const q 又被 const 修饰
  • 1.3、const 的使用场景(场景一用的居多)

    • 场景一:修饰全局变量,目的是:使外界无法修改变量,保持只读,提高预编译的速度和时间(苹果建议使用 const),如下:

      // 设置基础的url,这样来保证base_url的不变(封装请求的类)
      NSString * const base_url =  @"http://www.baodu.com/";
      
    • 场景二:修饰方法中的参数,如下

      -(void)constTest2{
           [self test:@"你好!"];
           int p = 1;
           [self test1:&p];
           [self test2:2];
      }
      
      // 当一个方法的参数,只读.
      -(void)test:(NSString * const)string{
           // 这句代码是报错的,被 const 修饰过后,string 是无法被修改的
           string = @"234";
      }
      // 指针只读,不能通过指针修改值
      - (void)test1:(int const *)a{
           //  *a = 11;
      }
      
      // 基本数据类型只读
      - (void)test2:(int const)a{
      
      }
      

二、宏 的简单使用

  • 2.1、基本概念:宏是一种批量处理的称谓。一般说来,宏是一种规则或模式,或称语法替换 ,用于说明某一特定输入(通常是字符串)如何根据预定义的规则转换成对应的输出(通常也是字符串)。这种替换在预编译时进行,称作宏展开。编译器会在编译前扫描代码,如果遇到我们已经定义好的宏那么就会进行代码替换,宏只会在内存中copy一份,然后全局替换,宏一般分为对象宏和函数宏,推荐博客

  • 2.2、宏的弊端:如果代码中大量的使用宏会使预编译时间变长。

  • 2.3、常用宏举例如下

    /** 1、屏幕的宽高 */
    #define JK_SCREEN_WIDTH  [UIScreen mainScreen].bounds.size.width
    #define JK_SCREEN_HEIGHT  [UIScreen mainScreen].bounds.size.height
    /** 2、判断是不是苹果手机 */
    #define JKIs_Iphone (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
    
  • 2.4、const与宏的区别?

    答:1.编译时刻 宏:预编译 const:编译;2.编译检查 宏没有编译检查,const有编译检查;3.宏的好处 定义函数,方法 const不可以;4.宏的坏处 大量使用宏,会导致预编译时间过长

    提示:

    • 预编译:在打开项目的时候上面会有一个加载项目的进度条就是预编译
    • 编译:command+R和command+B都是编译
    • 网上的误区:大量使用宏,会导致内存暴增(定义一个字符串的宏,赋值给多个变量,打印其内存地址,经过测试:宏定义的是常量,常量都放在常量区,只会生成一份内存,故网上说的都是不对的),如下图
      1728484-88fb433e245dfde1.jpeg
      网上误区

三、static 简单使用

  • 3.1、修饰局部变量

    • <1>、被static修饰局部变量,延长生命周期,跟整个应用程序有关,程序结束才会销毁,如下:在一个类的里面打印下面的方法,只要程序不销毁, a 的值就不会被销毁,会一直保持最后一次给 a 赋的值

      -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
      
            static int a = 0;
            ++a;
            NSLog(@"a=%d",a);
      }
      
    • <2>、被 static 修饰局部变量,只会分配一次内存,如下:从打印结果我们可以看到,a 的内存地址不会再变

      static int a = 0;
      ++a;
      NSLog(@"a = %d a的内存地址=%p",a,&a);
      部分打印结果:
      a = 1   a的内存地址=0x10e758160
      a = 2   a的内存地址=0x10e758160
      a = 3   a的内存地址=0x10e758160
      a = 4   a的内存地址=0x10e758160
      

      提示:被static修饰局部变量什么时候分配内存?程序一运行就会给static修饰变量分配内存

  • 3.2、修饰全局变量,被static修饰全局变量,作用域会修改,也就是只能在当前文件下使用

    #import "ViewController.h"
    
    static int b = 20;
    
    @interface ViewController ()
    
    @end
    
    @implementation TestViewController
    
    - (void)viewDidLoad {
         [super viewDidLoad];
    
        self.view.backgroundColor = [UIColor purpleColor];;
    }
    @end
    

四、extern 简单使用

  • 4.1、声明外部全局变量(只能用于声明,不能用于定义),举例如下:我们在类里面定义的全局变量,在其他的类里面使用的时候只要声明一下就好

    #import "ViewController.h"
    int x = 20;
    
    @interface ViewController ()
    
    @end
    
    @implementation TestViewController
    
    - (void)viewDidLoad {
          [super viewDidLoad];
    
          self.view.backgroundColor = [UIColor purpleColor];;
    }
    @end
    

    在其他类里面使用一,如下:声明一下即可

    #import "TestViewController.h"
    
    @interface TestViewController ()
    
    @end
    
    @implementation TestViewController
    
    - (void)viewDidLoad {
          [super viewDidLoad];
    
          self.view.backgroundColor = [UIColor purpleColor];;
    }
    
    extern int x;
    -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    
         NSLog(@"x的值是:%d",x);
         // 打印结果: x的值是:20
    }
    @end
    

    在其他类里面使用二,如下:在ViewController类的.h里面声明一下即可,如下:

    #import <UIKit/UIKit.h>
    
    @interface ViewController : UIViewController
    
    extern int x;
    
    @end
    
  • 4.2、extern工作原理:先会去当前文件下查找有没有对应全局变量,如果没有,才会去其他文件查找

五、static 与 const 联合使用

  • 5.1、回顾一下 static 与 const
    const:修饰全局变量
    static:修饰全局变量,修改作用域

  • 5.2、static 与 const 联合使用
    如果我们想这个 BASE_URL无法被其他类使用,那么我们就在前面加上 static 因为 static 修饰全局变量,修改作用域,只能在 UrlTest里面使用,再其他类里面使用是不可以的,切记:这个 BASE_URL 是在 .m 里面定义的

    #import "UrlTest.h"
    
    static NSString * const BASE_URL  =  @"http://www.baodu.com/";
    
    @implementation UrlTest
    
    @end
    

六、extern 与 const 联合使用

  • 6.1、开发中使用场景:在多个文件中经常使用的同一个字符串常量,可以使用extern与const组合。原因入下:

    • static与const组合:在每个文件都需要定义一份静态全局变量。
    • extern与const组合:只需要定义一份全局变量,多个文件共享。

    提示:开发中便于管理所有的全局变量,通常搞一个Global文件,里面专门定义全局变量,统一管理,要不然项目文件太多不好找。

  • 6.2、extern的基本使用 :当我们在一个防止一个变量被修改的时候,我们在前面加上 const,如下,仅仅是 BASE_URL无法被修改,在自己的.h文件里面 extern 声明一下即可,在其他类里面通过 导入 .h 文件,还是可以使用的 BASE_URL

    • UrlTest的.h文件 ( 声明 BASE_URL )

      #import "UrlTest.h"
      // 声明  BASE_URL
      extern NSString * const BASE_URL;
      
      @implementation UrlTest
      
      @end
      
    • UrlTest的.m文件

      #import "UrlTest.h"
      
      NSString * const BASE_URL  =  @"http://www.baodu.com/";
      
      @implementation UrlTest
      
      @end
      

      提示:定义全局的东西,遵循规定,顶一个以全局的文件来管理全局变量,以避免全局变量重复定义

  • 6.3、extern 的高级使用 (模仿 YYKIT 的使用 ),其实它只是把苹果的宏拿过来改改名字,看起来很牛逼,我们也可以牛逼一下,如下:

    • 苹果的定义:

      #ifdef __cplusplus
      #define UIKIT_EXTERN     extern "C" __attribute__((visibility ("default")))
      #else
      #define UIKIT_EXTERN         extern __attribute__((visibility ("default")))
      #endif
      
    • 我们只需要把 UIKIT_EXTERN 改为 JKKIT_EXTERN,那以后我们就可以使用我们自己定义的

      #ifdef __cplusplus
      #define JKKIT_EXTERN        extern "C" __attribute__((visibility ("default")))
      #else
      #define JKKIT_EXTERN            extern __attribute__((visibility ("default")))
      #endif
      
    • 苹果和我们自己定义的使用如下

      #import <Foundation/Foundation.h>
      #import <UIKit/UIKit.h>
      
      #ifdef __cplusplus
      #define JKKIT_EXTERN        extern "C" __attribute__((visibility ("default")))
      #else
      #define JKKIT_EXTERN            extern __attribute__((visibility ("default")))
      #endif
      
      // 使用自己定义的
      JKKIT_EXTERN NSString * const BASE_URL;
      // 使用苹果定义的 UIKIT_EXTERN
      // UIKIT_EXTERN NSString * const BASE_URL;
      
      NS_ASSUME_NONNULL_BEGIN
      
      @interface UrlTest : NSObject
      
      @end
      
      NS_ASSUME_NONNULL_END
      

转载于:https://www.jianshu.com/p/44615b9e433d

iOS extern

阅读数 2

没有更多推荐了,返回首页