美文网首页
读EffectiveObjective-C2.0(第三条、第四条

读EffectiveObjective-C2.0(第三条、第四条

作者: LazyLoad | 来源:发表于2020-10-20 09:28 被阅读0次

    第三条:多用字面量语法,少用与之等价的方法

    • NSStringNSNumberNSArrayNSDictionary都可以使用字面量的方式创建一个对象。相比于使用alloc及init方法创建对象简单了许多。字面量语法可以缩短代码长度,十分易读。
    NSString *someString = @"Effective Objective-C";
    
    • 字面数值(NSNumber):有些时候需要将整数、浮点数、布尔值封装成OC对象。这种情况下可以使用NSNumber类,该类提供了多种类型的包装方法。如果不使用字面量,那么就需要按照下面的方式进行对象包装:
    NSNumber *someNumber = [NSNumber numberWithInt:1];
    

    如果使用字面量,就会变得十分的简洁

    NSNumber *someNumber = @1;
    
    • 能够使用NSNumber表示的字面量有很多:
    NSNumber *intNumber = @1;
    NSNumber *floatNumber = @2.1;
    NSNumber *doubleNumber = @3.14159;
    NSNumber *boolNumber = @YES;
    NSNumber *charNumber = @'a';
    
    • 字面量语法也适用于表达式
    int x = 5;
    float y = 6.32;
    NSNumber *expressionNumber = @(x * y);
    
    • 字面数组(NSArray):如果不使用字面量语法来创建数组,代码如下:
    NSArray *animals = [NSArray arrayWithObjects:@"dog", @"cat", "mouse", @"badger", nil];
    

    使用字面量语法创建数组:简单、易操作

    NSArray *animals = @[@"dog", @"cat", @"mouse", @"badger"];
    
    • 通过下标获取数组中的元素,不使用字面量语法:
    NSString *dog = [animals objectAtIndex:0];
    

    使用字面量语法:

    NSString *dog = animals[0];
    

    这种方式明显更加简单,和其他语言获取元素方式相似。

    注意:使用字面量语法创建的数组中的元素不能为nil,如果数组中的元素为nil,就会抛出异常

    NSString *object1 = @"dog";
    NSString *object2 = @"cat";
    NSString *object3 = @"mouse";
    
    NSArray *array1 = [NSArray arrayWithObjects:object1, object2, object3, nil];
    NSLog(@"%@", array1);
    NSArray *array2 = @[object1, object2, object3];
    NSLog(@"%@", array2);
    

    上述代码:二者打印的结果是一致的,没有任何问题。

    • 如果将object2指向nil。array1不会抛出异常,array1只会打印object1,因为arrayWithObjects:这种方式创建的数组当发现元素为nil的时候,方法会提前结束。
    • array2会抛出异常,并终止程序的运行。二者对比来说,字面量语法创建数组更加安全,帮助我们及时的发现数组中的元素存在nil的情况。而前者的方式,不容易发现数组中的元素存在nil的情况。
    NSString *object1 = @"dog";
    NSString *object2 = nil;
    NSString *object3 = @"mouse";
    
    NSArray *array1 = [NSArray arrayWithObjects:object1, object2, object3, nil];
    NSLog(@"%@", array1);
    NSArray *array2 = @[object1, object2, object3];
    NSLog(@"%@", array2);
    
    • 字面量字典(NSDictionary):是一种映射型数据结构,相当于其他语言中的Map。可向其中添加键值对。
    • 使用非字面量语法创建字典:这种方式创建是**Value -> Key **,和通常情况理解的键值对相反,不是很方便。
    NSDictionary *personData = [NSDictionary dictionaryWithObjectsAndKeys:@"Matt", @"firstName", @"Galloway", @"lastName", [NSNumber numberWithInt:28], @"age", nil];
    
    • 使用字面量语法创建字典:明显比上面的方式清晰,简洁
    NSDictionary *personData = @{
        @"firstName": @"Matt",
        @"lastName": @"Galloway",
        @"age": @28
    };
    

    注意:字典和数组中的元素都必须是对象类型,与数组一样,使用字面量语法创建的字典,如果遇到nil,便会抛出异常,而dictionaryWithObjectsAndKeys:方法会在遇到nil之前的时候停下。

    • 字典也可以向数组一样通过字面语法进行元素的访问,字面量语法更加方便
    NSString *lastName = [personData objectForKey:@"lastName"]; // 非字面语法
    NSString *lastName = personData[@"lastName"]; // 字面量语法
    

    第四条:多用类型常量,少用#define预处理指令

    编写代码时经常使用到常量。例如:设置视图的动画时长,而且动画时长在多个位置都会使用到。通常会把时长抽取为常量,在需要的位置直接调用即可,方便管理。

    我们也许会使用这种预处理指令来实现:

    • 使用这种预处理指令的方式会把源代码中的ANIMATION_DURATION字符串替换为0.3。这可能是我们想要的一种结果,但是这样定义出来的常量没有类型信息。动画时间与时间相关,但是在代码中没有明确指出类型。
    • 预处理过程会把碰到的所有ANIMATION_DURATION一律替换成0.3,这样的话,假设此指令声明在某个头文件中,那么所有引入这个头文件的代码,其ANIMATION_DURATION都会被替换。
    #define ANIMATION_DURATION 0.3
    
    • 要解决此问题,可以使用类型常量:
    • 这种定义方式包含类型信息,清晰的描述了常量的含义
    static const NSTimeInterval kAnimationDuration = 0.3;
    
    • 注意常量的名称。常用的命名法是:如果常量局限于某一个编译单元(实现文件)之内,则在前面加字母k;如果常量在类之外的多个文件可见,则通常以类名为前缀

    • 定义常量的位置很重要,不要在头文件中声明预处理指令和static const 定义的常量。当多个地方引入该头文件的时候,会将定义的常量引入,而常量不一定就是被需要的,而且,常量的名称有可能互相冲突。如果要定义全局的常量,最好加上前缀,因为OC没有命名空间的概念,不加前缀很可能导致命名的冲突。

    • 如果不打算公开某个常量,应该将其定义在使用该常量的实现文件中。比如说执行动画的时间一般情况下都是时间常量即可。

    // EOCAnimatedView.h
    #import <UIKit/UIKit.h>
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface EOCAnimatedView : UIView
    
    - (void)animate;
    
    @end
    
    NS_ASSUME_NONNULL_END
    
    // EOCAnimatedView.m
    #import "EOCAnimatedView.h"
    
    static const NSTimeInterval kAnimationDuration = 0.3;
    
    @implementation EOCAnimatedView
    
    - (void)animate {
      [UIView animateWithDuration:kAnimationDuration animations:^{
          // do something
      }];
    }
    
    @end
    
    • 变量一定要使用staticconst声明。
      • 使用const修饰符声明的变量,是不允许修改的,编译器会报错。
      • 使用static修饰符声明的变量,只能在定义次变量的实现文件(.m)文件中可见。

    所以kAnimationDuration变量的作用域,只在EOCAnimatedView.m中。

    • 如果声明此变量的时候没有加static,编译器会为它创建一个外部符号。此时在另一个实现文件中也声明了相同的变量,那么编译器就会报错。
    duplicate symbol '_kAnimationDuration' in:
    ViewController.o
    EOCAnimatedView.o
    ld: 1 duplicate symbol for architecture x86_64
    clang: error: linker command failed with exit code 1 (use -v to see invocation)
    

    所以,同时使用staticconst声明一个变量,不会创建外部符号,也保证了变量不可以被修改,还包好了类型信息,好处非常多的。

    • 有的时候我们不得不需要公开某个常量。比如说使用NSNotificationCenter的通知处理,要在多个文件中定义相同的Key。这种常量,需要放在全局符号表中,以便可以在定义该常量的实现文件之外使用。通常情况下,我的做法如下:

      • 创建一个const文件(名称可以自己起),包含声明文件和实现文件。
      • 变量在头文件中声明在实现文件中定义
      // const.h
      extern NSString *const EOCStringConstant; //!< 注释内容
      // const.m
      NSString *const EOCStringConstant = @"Value";
      
      • 编译器看到头文件中的extern关键字,就知道如何在引入头文件的代码中处理该常量了。这个关键字告诉编译器,在全局符号表中将会有一个名字叫做EOCStringConstant的符号。
    • 因为符号要放在全局符号表中,命名要格外注意。通常用相关的类名作为前缀。类似系统定义的UIApplicationDidEnterBackgroundNotification这种方式。见名知意。

    相关文章

      网友评论

          本文标题:读EffectiveObjective-C2.0(第三条、第四条

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