[iOS] 语法语义关键词等 (2)

目录:

  1. static作用
  2. 各种各样的nullable
  3. if 和 switch的区别
  4. __auto_type
  5. interface和protocol
  6. null & kCFNull
  7. ObjC的BOOL为什么要用YES、NO而不建议用true、false

1. static作用

Effective OC里面也说过static,这里再复习一下~ 可参考:https://www.jianshu.com/p/9c09989b6862

如果是static的局部变量,是会在app生命周期内有效的,也就是app销毁的时候才会销毁,即使作用域是在花括号内。

如果是全局变量呢?默认情况下,全局变量在整个程序中是可以被访问的(即全局变量的作用域是整个项目文件)

static修饰全局变量,是为了让这个变量的作用域局限在当前文件内。防止两个不同的文件里面定义了相同名字的一个全局变量那么就会报错duplicate definition

  • 那么一个问题是,static修饰的属性是在堆上还是栈上嘞?
    全局区(静态区) (static) 全局变量和静态变量的存储是放在一起的,初始化的全局变量和静态变量存放在一块区域,未初始化的全局变量和静态变量在相邻的另一块区域,程序结束后有系统释放。
    => 关于内存分配可以参考:https://www.jianshu.com/p/f3c1b920e8eb

  • 另一个point是extern是干啥得嘞?
    即使你不import一个定义了全局变量的文件,仍旧可以用extern得到该变量,也就是说extern可以脱离import访问所有全局变量(除开用static修饰的作用域仅在当前文件内的全局变量)

  • app生命周期内的变量声明
    如果有app整个生命周期只需要执行一次的事情,我一般都会想到dispatch_once,但如果是一个特定次数嘞?就需要用全局变量计次啦,这个时候就可以用static来做全局变量,加到去干活儿的类里面就可以了~


2. 各种各样的nullable

由于Swift里面的变量都会指定是不是空,所以Objective-C为了和Swift兼容,每个属性或每个方法都去指定nonnull和nullable。

苹果为了减轻我们的工作量,定义了NS_ASSUME_NONNULL_BEGIN和NS_ASSUME_NONNULL_END两个宏。在这两个宏之间的所有简单指针对象都被假定为nonnull。

可参考:https://www.jianshu.com/p/d001550fadd4

那么修饰词有哪些呢?
nullable、nonnull、null_resettable、_Null_unspecified以及首字母大写的那种

偷懒直接借过来啦:

  1. nullable,表示属性可以为空
    修饰属性的时候用nullable,修饰参数的时候在星号后面加_Nullable或者__nullable
@property (nonatomic, copy, nullable) NSString *name;
@property (nonatomic, copy) NSString *_Nullable name;
@property (nonatomic, copy) NSString *__nullable name;

  1. nonnull,表示属性不能为空
    同上类似
@property (nonatomic, copy, nonnull) NSString *name;
@property (nonatomic, copy) NSString *_Nonnull name;
@property (nonatomic, copy) NSString *__nonnull name;

  1. null_resettable,表示可以重新设置空,set方法可以为空,get不能为空
@property (nonatomic, copy, null_resettable) NSString *name;

必须重写get或set方法,做判空处理

- (NSString*)name{
        if (_name == nil){
                _name = @"不能为空";
        }
        return _name;
}
  1. _Null_unspecified,不确定是否为空
@property (nonatomic, strong) NSString * _Null_unspecified name;

3. if 和 switch的区别

if 和 switch 相比大家肯定会prefer switch,他俩的确也是有性能差异的,但为啥switch会比if好呢?

可参考:https://blog.csdn.net/hixiaogui/article/details/79785920
https://blog.csdn.net/xi_niuniu/article/details/45101093

  • if:
    比较中规中矩,会一条一条的向下执行,直到条件满足,执行完函数体就结束

  • switch:分俩种情况
    1.当case语句数量<4 时,效率上和if语句基本一样
    2.当case语句数量>=4时,case会有一个跳转表,存储着每个case和对应的跳转体的地址,效率明显比if效率高。

switch 指令是一个有索引的跳转,而if ... else 是无索引的跳转。if...else 是 O(N)级别的,switch ... case 是 O(1)级别的。

我理解其实就类似一个数组,然后根据switch的值去找case,所以就很target定位到case啦~ 具体原理欢迎还是看refer吧,我感觉我的汇编水准理解不到那个层次QAQ

switch

举个例子~

- (void)testSwitchIf {
    NSInteger i = 9;
    NSTimeInterval start = [[NSDate date] timeIntervalSince1970];
    if (i == 1) {
        NSLog(@"i == 1");
    } else if (i == 2) {
        NSLog(@"i == 2");
    } else if (i == 3) {
        NSLog(@"i == 3");
    } else if (i == 4) {
        NSLog(@"i == 4");
    } else if (i == 5) {
        NSLog(@"i == 5");
    } else if (i == 6) {
        NSLog(@"i == 6");
    } else if (i == 7) {
        NSLog(@"i == 7");
    } else if (i == 8) {
        NSLog(@"i == 8");
    } else if (i == 9) {
        NSLog(@"i == 9");
    } else if (i == 10) {
        NSLog(@"i == 10");
    }
    NSTimeInterval timeConsume = [[NSDate date] timeIntervalSince1970] - start;
    NSLog(@"if time consume:%f", timeConsume);
    
    start = [[NSDate date] timeIntervalSince1970];
    switch (i) {
        case 1:
            NSLog(@"i == 1");
            break;
            
        case 2:
            NSLog(@"i == 2");
            break;
        
        case 3:
            NSLog(@"i == 3");
            break;
            
        case 4:
            NSLog(@"i == 4");
            break;
            
        case 5:
            NSLog(@"i == 5");
            break;
            
        case 6:
            NSLog(@"i == 6");
            break;
        
        case 7:
            NSLog(@"i == 7");
            break;
            
        case 8:
            NSLog(@"i == 8");
            break;
                
        case 9:
            NSLog(@"i == 9");
            break;
            
        case 10:
            NSLog(@"i == 10");
            break;
            
        default:
            break;
    }
    
    timeConsume = [[NSDate date] timeIntervalSince1970] - start;
    NSLog(@"switch time consume:%f", timeConsume);
}

===

输出:
2020-06-14 20:36:21.092568+0800 Example1[31090:6201959] if time consume:0.000059
2020-06-14 20:36:21.092617+0800 Example1[31090:6201959] switch time consume:0.000020

switch会比if快了1/3的样子~ 所以日常一定记得能switch就别if哦~


4. __auto_type类型推导

参考:https://www.jianshu.com/p/551908b48bb0

其实就是类似swift里面的var,酱紫你就可以直接定义对象了,不用声明它的类型,会自动根据值来获取类型~ 我们的小哥哥反正其实没啥用,稍微简写了一点儿主要是显得高大上...

    __auto_type string = @"test";
    __auto_type subString = [string substringFromIndex:1];
    NSLog(@"%@",subString);
//正常写法
    void(^testBlock)(NSString *,NSNumber *) = ^(NSString *string,NSNumber *number){
        NSLog(@"testBlock %@ - %@",string,number);
    };
//类型推导
    __auto_type test = ^(NSString *string,NSNumber *number){
        NSLog(@"__auto_type %@ - %@",string,number);
    };
    testBlock(@"1",@(2));
    test(@"3",@(4));

  • 还有一个花式写法可以避免view名字过长不断重复写这个view的名字~ 也是装逼利器~
UIView *seperateView = ({
        UIView *view = [[UIView alloc] init];
        view.backgroundColor = mRGBColor(233, 233, 233);
        [contentView addSubview:view];
        [view mas_makeConstraints:^(MASConstraintMaker *make) {
            make.left.width.equalTo(contentView);
            make.height.equalTo(@0.5);
            make.top.equalTo(contentView).offset(47.5);
        }];
        view;
    });

5. interface和protocol

OC中@interface+@implements共同构成一个类,不能只有一个哦,必须成对存在;而@protocol作为一个接口,可以没有实现。

这个是我忘记写implements报错遇到的一个问题捂脸0.0

编译错误筛选

6. nil & kCFNull

参考:https://www.jianshu.com/p/3aaefb3bcf73

我看代码解析后端返回的时候用的kCFNull判空,小哥哥说其实就是后端的null解析以后就变成kCFNull了,于是我查了一下~

  • nil: define the id of a null instance, 指向一个(实例)对象的空指针
    NSString *str = nil;
    NSDate *date = nil;

  • Nil:defines the id of a null class, 指向一个类的空指针
    Class class = Nil;

  • NULL:定义其他类型(基本类型,C类型)的空指针
    char *p = NILL;

  • NSNull:数组中元素的占位符, 数据中的元素不能为nil(可以为空,也就是NSNull)
    原因:nil 是组数的结束标识
    如果使用nil,在n个数组中的第k个,那个数组的长度就只有 k 个元素。

  • kCFNull: NSNull 的单例

NSNull *null1 = (id)kCFNull;
NSNull *null2 = [NSNull null];
NSNull *null3 = [NSNull null];

地址:
null1   NSNull *    0x1ffcdfe28 0x00000001ffcdfe28
null2   NSNull *    0x1ffcdfe28 0x00000001ffcdfe28
null3   NSNull *    0x1ffcdfe28 0x00000001ffcdfe28

但是其实你如果想BOOL i = nil;也是OK的,写代码的时候不会有很大的差异。但是NSNull作为占位空对象和nil还是有区别的:

nil: 作为对象的空指针和数组的结束标志
NSNull: 作为数组中的空值占位符


7. ObjC的BOOL为什么要用YES、NO而不建议用true、false

可以参考:https://blog.csdn.net/weixin_34292287/article/details/87975252

这个问题吧是凌哥哥问我的,但是吧其实OC就是用YES和NO啊,其他就都是true false,就很理所当然自己也没觉得有啥疑问,所以凌哥问了以后我就查了一下~

首先看下BOOL的定义:

#if TARGET_OS_OSX || (TARGET_OS_IOS && !__LP64__ && !__ARM_ARCH_7K)
#   define OBJC_BOOL_IS_BOOL 0
#else
#   define OBJC_BOOL_IS_BOOL 1
#endif
 
#if OBJC_BOOL_IS_BOOL
    typedef bool BOOL;
#else
#   define OBJC_BOOL_IS_CHAR 1
    typedef signed char BOOL; 
#endif

可以近似的理解为在 64-bit 设备上 BOOL 实际是 bool 类型,在 32-bit 设备上 BOOL 的实际类型是 signed char


那么 YES / NO 又分别是什么值呢?我们看一下具体的定义:

#if __has_feature(objc_bool)#define YES __objc_yes#define NO  __objc_no#else#define YES ((BOOL)1)#define NO  ((BOOL)0)#endif复制代码

这里要先看一下 __objc_yes__objc_no 是什么值,我们在 LLVM 的文档中可以得到答案:

The compiler implicitly converts __objc_yes and __objc_no to (BOOL)1 and (BOOL)0\. The keywords are used to disambiguate BOOL and integer literals.复制代码

__objc_yes__objc_no 其实就是 (BOOL)1(BOOL)0,这么写的原因就是为了消除 BOOL 和整型数的歧义而已。

(BOOL)1(BOOL)0 这个大家应该也都能很容易理解了,其实就是把 1 和 0 强转成了 BOOL 对应的实际类型。

所以综上所述为了类型的正确对应,在给 BOOL 类型设值时要用 YES / NO,其实就是为了类型对应以及消除 BOOL 和整型数的歧义。


true / false 是什么?

#define bool _Bool
#define true 1
#define false 0
  • 那么为什么要对 BOOL 用 YES / NO 而不是 true / false?
  1. 可以看到 ObjC 是自己定义了 BOOL 的类型,然后定义了对应要使用的值 YES / NO,理所当然的第一个原因是我们要按照标准来。

  2. 既然 ObjC 的 BOOL 使用的不是标准 C 的定义,那么以后这个定义可能还会修改。虽然说概率很低,但是毕竟从上面的代码看就经历了 signed char 到 bool 的一次修改不是么?为了避免这种风险,建议还是要使用 YES / NO。

  3. 在某些情况下,类型不匹配会导致 warning,而 YES / NO 是带类型的,可以保证类型正确,所以建议要用 YES / NO。

  • 注意不要用==YES这种

在32位的机子上,BOOL是signed char类型,所以会有下面的问题:

BOOL a = 2;
if (a) {
    NSLog(@"a is YES");
} else {
    NSLog(@"a is NO");
}
if (a == YES) {
    NSLog(@"a == YES");
} else {
    NSLog(@"a != YES");
}

32位机子输出:
a is YES
a != YES

因为其实翻译过来是酱紫的:

signed char a = 2;
if (a == (signed char)1) {
    NSLog(@"a == YES");
} else {
    NSLog(@"a != YES");
}
  • 这就对应了另外一个问题了,在网络请求的时候,我们经常要传给后端一个bool参数,例如xxx=true。这个时候传入{@"xxx" : @"true"}{@"xxx" : @(YES)}的区别是啥呢?
    如果你用{@"xxx" : @(YES)}那么翻译为param就变为了xxx=1因为YES其实就是1,但{@"xxx" : @"true"}会翻译为xxx=true
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,539评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,911评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,337评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,723评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,795评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,762评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,742评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,508评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,954评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,247评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,404评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,104评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,736评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,352评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,557评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,371评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,292评论 2 352