iOS - OC 语言新特性

简介: 前言相对于 Java,OC 语言是一门古老的语言了,而它又是一门不断发展完善的语言。一些新的编译特性,为 OC 语言带来了许多新的活力。在 Xcode7 中,iOS9 的 SDK 已经全面兼容了 Objective-C 的一些新特 性和新功能。

前言

  • 相对于 Java,OC 语言是一门古老的语言了,而它又是一门不断发展完善的语言。一些新的编译特性,为 OC 语言带来了许多新的活力。在 Xcode7 中,iOS9 的 SDK 已经全面兼容了 Objective-C 的一些新特 性和新功能。这些功能都只作用于编译期,对程序的运行并没有影响,因此,它可以很好的向下进行兼容,无缝的衔接低版本的 iOS 系统,如果可以将这些新特性都应用于开发,开发效率和代码质量,相比之前会有一个很大的提升。

1、可选类型检测

  • 在 swift 语言中,通过 ! 和 ? 可以将对象声明成 Optional,用于在开发中标记这个对象是否可以为空。在 OC 中,以前是没有这样的功能的,因此我们在开发中会经常遇到因为某个函数应该返回实例而返回了空导致的崩溃。Nullability 的主要用武之地,就是在这里,它可以起到提示开发者做是否为空的判断的提示。这一特性在 Xcode6.3 中就已经支持,但在 Xcode7 中又做了一些写法上的小改动。

  • Xcode7 中,系统的框架中已经支持了 Nullability,如下所示,这是 NSArray 中的两个属性,其中 nullable 关键字说明了这里可能返回空的值。

        @property (nullable, nonatomic, readonly) ObjectType firstObject;
        @property (nullable, nonatomic, readonly) ObjectType lastObject;
  • 如果仅仅是在返回值中给开发者一些提示,可能觉得应用并不大,对开发者最大的帮助是这一特性可以用于函数的参数中,这样我们在调用函数时起到的提示作用,将是非常重要的,越是多人合作的项目,作用也越大。例如以下方法中,我们在调用函数时,如果传入了空值,编译器会给我们警告。

        - (void)setName:(NSString * _Nonnull)name {
    
        }
  • 修饰参数:

    • 属性声明中:

          nonnull             不可为空
          nullable            可以为空
          null_unspecified    不确定是否可以为空(极少情况)
          null_resettable     set 方法可以为 nil,get 方法不可返回 nil,只能用在属性的声明中。
    • 方法(函数)参数中:

          _Nonnull            不可为空
          _Nullable           可以为空
          _Null_unspecified   不确定是否可以为空(极少情况)
  • iOS9 的 SDK 中已经完全兼容使用了这些特性,并且 nonnull 的使用会比 nullable 广泛的多,系统提供了这样一对宏,我们在这对宏之间定义的变量都会加上 nonnull 的修饰符,只有我们特殊声明 nullable 的才需要手动写。

        #define NS_ASSUME_NONNULL_BEGIN _Pragma("clang assume_nonnull begin")
    
        #define NS_ASSUME_NONNULL_END   _Pragma("clang assume_nonnull end")
        #import <Foundation/Foundation.h>
    
        NS_ASSUME_NONNULL_BEGIN
    
        @interface NSData (FormData)
    
        - (void)q_setHttpHeaderFieldWithRequest:(NSMutableURLRequest *)request fileBoundary:(nullable NSString *)fileBoundary;
    
        @end
    
        NS_ASSUME_NONNULL_END

2、泛型

  • Xcode 7 对系统中常用的一系列容器类型都增加了泛型支持(),有了泛型后就可以指定容器类中对象的类型了。假如向泛型容器中加入错误的对象,编译器会报警告。

    • 泛型声明格式:在声明类的时候,在类型后面
    • 泛型定义格式:放在限制的类型后面

    • 泛型好处:
      • 1、提高程序员开发规范,一看就知道是什么类型。
      • 2、限制类型,不允许传入其他的类型。
      • 3、从集合中取出来,直接可以使用点语法。
    • 泛型开发中使用场景:
      • 1、一般都是用来限制集合类型。
    • 泛型不定义就是 id。
    • 泛型定义是独立,只能修饰当前对象。

    • 疑问:谁才能使用泛型?只要声明了泛型的类,才能定义。

    • 自定义泛型:
      • 开发中使用场景:当声明一个类,有个属性不确定类型,当创建对象的时候才确定这个属性是什么类型的时候,就才可以采取使用泛型。

2.1 有类型约定的集合

  • 在 Xcode7 中,我们可以给集合类型添加一个泛型的约定,如下,声明了这样一个数组后,就好比告诉了编译器,这个数组中的数据类型都是 NSString 类型的。

        NSMutableArray<NSString *> *array = [[NSMutableArray alloc] init];
    • 如果用这个数组中元素的方法,会出现如下提示。使用点语法可以访问到数组中泛型的方法了。

      OcNew1

    • 在我们向这个数组中追加元素的时候,编译器将元素的类型提示了出来,并且将 FromArray 方法中需要的元素类型也提示了出来。

      OcNew2

    • 同样,如果我们向这个数组中追加类型不匹配的元素,如下,编译器会给我们一个警告。

      OcNew3

2.2 类型通配符

  • 观察 Xcode7 中 iOS 系统的类,我们可以发现这么一个好玩的东西:ObjectType。它既不是一个类型,也不是关键字,然而却大量存在,如下是系统的 NSMutableArray 的头文件。这个 ObjectType 其实只是一个类型标识符,它具体怎么写并不重要,只是系统中都约定使用了 ObjectType,你也可以在自己的类中按自己的喜好来命名。

        @interface NSMutableArray<ObjectType> : NSArray<ObjectType>
        - (void)addObject:(ObjectType)anObject;
        - (void)insertObject:(ObjectType)anObject atIndex:(NSUInteger)index;
        - (void)removeLastObject;
        - (void)removeObjectAtIndex:(NSUInteger)index;
        - (void)replaceObjectAtIndex:(NSUInteger)index withObject:(ObjectType)anObject;
        - (instancetype)init NS_DESIGNATED_INITIALIZER;
        - (instancetype)initWithCapacity:(NSUInteger)numItems NS_DESIGNATED_INITIALIZER;
        - (nullable instancetype)initWithCoder:(NSCoder *)aDecoder NS_DESIGNATED_INITIALIZER;
        @end
  • 创建一个类,继承于 NSObject,取名叫 MyArray:

        // MyArray.h
    
            #import <Foundation/Foundation.h>
    
            // 这个类型通配符只能在 interface 里使用,作用域为 @interface 到 @end 之间,这里我使用 Type 来做这个通配符
            @interface MyArray<Type> : NSObject             
    
            @property(nonatomic, retain, nonnull) NSMutableArray<Type> *array;
    
            - (void)addObject:(nonnull Type) obj;
    
            @end
    
        //  MyArray.m
    
            @implementation MyArray
    
            - (void)addObject:(id) obj {
    
                [_array addObject:obj];
            }
    
            - (instancetype)init {
    
                self = [super init];
                if (self) {
    
                    _array = [[NSMutableArray alloc] init];
                }
                return self;
            }
    
            - (NSString *)description {
    
                NSMutableString * str = [[NSMutableString alloc] init];
    
                for (int i = 0; i < _array.count; i++) {
    
                    [str appendString:[NSString stringWithFormat:@"%@\n", _array[i]]];
                }
                return str;
            }
    
            @end
  • 我们在使用这个自定义的集合类型时,就会有和系统一样的效果了:

    OcNew4

2.3 多参数的泛型集合

  • 多参数的泛型集合,有一个非常好的例子,就是 NSDictionary,在 Xcode7 中我们可以这样写字典。可以看到,字典键值的类型编译器为我们提示了出来,结合上面类型通配符的使用,对于多参的集合,将参数类型用 “,” 隔开即可。

    OcNew5

2.4 协变性与逆变性

  • 因为有了泛型集合的概念,相比之前,我们的类型实际上更加复杂了,比如还拿我们自定义的集合类型来举例,array 和 muArray 在编译器看来已经是不同的类型,如果我们强行转换,会报如下的警告:

        MyArray<NSString *> *array;
        MyArray<NSMutableString *> *muArray;


    OcNew6

  • 因此,就有了逆变和协变这个概念,不指定泛型类型的对象可以和任意泛型类型转化,但指定了泛型类型后,两个不同类型间是不可以强转的,假如你希望主动控制转化关系,就需要使用泛型的协变性和逆变性修饰符。

        __covariant     :协变性,子类型可以强转到父类型(里氏替换原则)。
        __contravariant :逆变性,父类型可以强转到子类型。
  • 上面的情况,我们将自定义的类做如下修改,就不会出现警告:

        // MyArray.h
    
            #import <Foundation/Foundation.h>
    
            // 在 @interface 中加入 __covariant 协变性
            @interface MyArray<__covariant Type> : NSObject
    
            @property(nonatomic, retain, nonnull) NSMutableArray<Type> *array;
    
            - (void)addObject:(nonnull Type) obj;
    
            @end
    
            MyArray<NSString *> *array;
            MyArray<NSMutableString *> *muArray;
    
            // NSMutableString 是 NSString 的子类
            array = muArray;
  • NSMutableString 是 NSString 的子类,在 MyArray 定义中加入了 __covariant 可以进行转换。但将 MyArray<NSString *> 转换为 MyArray<NSMutableString *> 时仍会报警告。

    OcNew7

3、类型延拓符

  • 在开发中,开发者经常会遇到这样的情况,例如通过 tag 获取某些 UI 控件时,viewWithTag 方法通常会返回给我们一个 UIView 类型的指针,这就需要开发者手动的强转一下,十分麻烦。新增加的 __kindof 修饰符可以帮助我们解除这个烦恼。

        // MyArray.h
    
            #import <Foundation/Foundation.h>
    
            @interface MyArray<__covariant Type> : NSObject                                     
    
            @property(nonnull, retain, nonatomic) NSMutableArray<UIView *> * viewArray;
    
            @property(nonatomic, retain, nonnull) NSMutableArray<Type> *array;
    
            - (void)addObject:(nonnull Type) obj;
    
            @end
    • 创建一个自定义的数组对象,并向其中添加一个 UIButton,我们会看到有如下一个警告:

      OcNew8

    • 这也是我们开发中常遇到的问题,以前需要强转。但是以后就不需要了,我们在声明这个数组时加上一个 __kindof 修饰符。警告就消失了,这个修饰符就是告诉编译器,这里可以返回 UIView 的子类指针。

          @property(nonnull, retain, nonatomic) NSMutableArray<__kindof UIView *> * viewArray;
  • id,instancetype,__kindof 作为返回值时的比较:

        id:
            优点:可以调用任何对象方法。
            缺点:不能使用点语法,不能做编译检查。
    
            Xcode5 之前,返回 id。
    
        instancetype:
            优点:会自动识别当前类的对象.
    
            Xcode5 instancetype。
    
        __kindof:
            优点:调用方法时,通过返回值提示,可以看到具体的返回类型,如:Person *,而前两者不会看到。
    
            xcode7 __kindof:表示当前类或者子类。
目录
相关文章
|
2月前
|
安全 Android开发 iOS开发
安卓与iOS的较量:技术特性与用户体验的深度解析
在移动操作系统的战场上,安卓和iOS一直占据着主导地位。本文将深入探讨这两大平台的核心技术特性,以及它们如何影响用户的体验。我们将从系统架构、应用生态、安全性能和创新功能四个方面进行比较,帮助读者更好地理解这两个系统的异同。
70 3
|
4月前
|
Android开发 Swift iOS开发
探索Android与iOS开发的差异性:平台特性与用户体验的深度剖析
【7月更文挑战第27天】在移动应用开发的广阔天地中,Android和iOS两大阵营各自占据半壁江山。本文将深入探讨这两个平台在开发过程中的关键差异,从编程语言、工具集到用户界面设计原则,以及它们如何影响最终的用户体验。通过对比分析,我们将揭示每个平台的独特优势,并讨论如何在这些差异中寻找平衡点,以实现跨平台的成功。
|
12天前
|
安全 API Swift
探索iOS开发中的Swift语言之美
【10月更文挑战第23天】在数字时代的浪潮中,iOS开发如同一艘航船,而Swift语言则是推动这艘船前进的风帆。本文将带你领略Swift的独特魅力,从语法到设计哲学,再到实际应用案例,我们将一步步深入这个现代编程语言的世界。你将发现,Swift不仅仅是一种编程语言,它是苹果生态系统中的一个创新工具,它让iOS开发变得更加高效、安全和有趣。让我们一起启航,探索Swift的奥秘,感受编程的乐趣。
|
1月前
|
安全 Swift iOS开发
探索iOS开发中的Swift语言之美
在数字时代的浪潮中,移动应用已成为日常生活的延伸。本文将深入探讨iOS平台上的Swift编程语言,揭示其背后的设计哲学、语法特性以及如何利用Swift进行高效开发。我们将通过实际代码示例,展示Swift语言的强大功能和优雅简洁的编程风格,引导读者理解并运用Swift解决实际问题。
|
2月前
|
监控 Android开发 iOS开发
深入探索安卓与iOS的系统架构差异:理解两大移动平台的技术根基在移动技术日新月异的今天,安卓和iOS作为市场上最为流行的两个操作系统,各自拥有独特的技术特性和庞大的用户基础。本文将深入探讨这两个平台的系统架构差异,揭示它们如何支撑起各自的生态系统,并影响着全球数亿用户的使用体验。
本文通过对比分析安卓和iOS的系统架构,揭示了这两个平台在设计理念、安全性、用户体验和技术生态上的根本区别。不同于常规的技术综述,本文以深入浅出的方式,带领读者理解这些差异是如何影响应用开发、用户选择和市场趋势的。通过梳理历史脉络和未来展望,本文旨在为开发者、用户以及行业分析师提供有价值的见解,帮助大家更好地把握移动技术发展的脉络。
80 6
|
2月前
|
安全 Swift iOS开发
探索iOS开发之旅:Swift语言的魅力与挑战
【9月更文挑战第21天】在这篇文章中,我们将一起潜入iOS开发的海洋,探索Swift这门现代编程语言的独特之处。从简洁的语法到强大的功能,Swift旨在让开发者能够以更高效、更安全的方式构建应用程序。通过实际代码示例,我们会深入了解Swift如何简化复杂任务,并讨论它面临的挑战和未来的发展方向。无论你是初学者还是有经验的开发者,这篇文章都将为你提供新的视角和知识。
44 4
|
1月前
|
开发工具 Android开发 iOS开发
移动应用开发的艺术:探索Android与iOS的操作系统特性
【9月更文挑战第33天】在数字时代的浪潮中,移动应用已成为我们日常生活不可或缺的一部分。本文将深入探讨两个主流移动操作系统——Android和iOS——的独特特性,并分析它们如何影响移动应用的开发过程。我们将通过比较这两个系统的设计哲学、用户界面(UI)设计、开发工具以及市场策略,来揭示开发者如何在这些不同的平台上打造出色的用户体验。无论你是开发者还是对移动技术感兴趣的读者,这篇文章都将为你提供宝贵的见解。
|
2月前
|
安全 Android开发 iOS开发
安卓与iOS的较量:技术特性与用户体验的深度剖析
在移动操作系统的战场上,安卓和iOS一直是两个重量级选手。本文将深入探讨两者的技术架构、安全性、应用生态以及用户体验等方面的差异,并尝试从用户和开发者的角度出发,分析这两个系统的优势与不足。通过比较,我们不仅能更好地理解各自的特点,还能洞察未来移动技术的发展趋势。
64 3
|
4月前
|
Android开发 Swift iOS开发
探索Android与iOS开发的差异:平台特性与用户体验
【7月更文挑战第30天】在移动应用开发的广阔天地中,Android与iOS两大平台各自展现出独特的魅力与挑战。本文将深入探讨这两个操作系统在开发环境、编程语言、用户界面设计以及发布流程等方面的主要差异,旨在为开发者提供一个清晰的对比视角,帮助他们根据项目需求和目标受众做出更明智的开发决策。
51 13
|
3月前
|
安全 Android开发 iOS开发
探索安卓与iOS开发的差异:平台特性与用户体验的比较
【8月更文挑战第19天】 在移动应用开发的广阔天地中,安卓与iOS两大平台各领风骚。本文将深入探讨这两个平台在开发过程中的关键差异,从编程语言和工具到用户界面设计,再到市场分布和安全性考虑。我们将一窥究竟,是什么让安卓开发如此灵活多变,又是什么让iOS开发显得精致而统一。通过这篇比较分析,开发者可以更清晰地认识到各自平台的优势和挑战,从而做出更明智的开发决策。
38 0