iOS - Swift Swift 语言新特性

一、Swift 2.0 带来哪些新变化

  • 常规变化:编程

    • 一、OS X 10.十一、iOS 9 和 watchOS 2 SDK 采纳了一些 Objective-C 的特性用来提升 Swift 的编程体验, 如可空性、类型化集合和一些别的特性。swift

    • 二、编译器对冗余的协议一致性,未被使用的绑定值以及能够设为常量的变量这些状况目前会给予警告或报错。数组

    • 三、修复了跨文件协议遵循时符号不可见或者重复的错误。闭包

    • 四、Swift 语言的调用约定更加智能,可以理解 API 所发生的变化和 Swift 所给出的警告。并发

    • 五、便利的可失败构造器(failable initializer)能够先返回 nil,而没必要首先调用 self.init。这是有利的一 面,但指定了构造器在返回 nil 前仍要给全部字段初始化。app

    • 六、find 函数更名为 indexOfsort 则变成了 sortInPlacesorted 变成了 sort框架

    • 七、String.toInt() 重名为 Int(String) 的可失败构造器,由于构造器语法更适合类型转换。异步

      • String 类型再也不遵循 SequenceType,可使用 .characters.utf8.utf16 对应字符集的运算。容许对泛型添加公共扩展。async

      • 字符串长度长度计算由 count(String) 变为 String.characters.count编程语言

      • 字符串裁剪由 code.substringToIndex(advance(code.startIndex, 6)) 变为 let endIndex = code.startIndex.advancedBy(6) code.substringToIndex(endIndex)

    • 八、标准库中重构了不少泛型的全局函数(如 mapfiltersort),采用协议扩展方式增长这些方法。这个好处是对于其余的关联类型能很好的适配。

      • 非泛型类类型能够继承泛型类(强制类型参数固定)。

      • 修复了 Swift 中泛型需求打印时 “T==T” 的错误。

      • 在泛型函数中声明了类型参数可是在函数中没有使用时将产生一个编译时错误,例如:

      • func foo<T> () {} // error:generic parameter ’T’ is not used in function signature

    • 九、基本上可使用 enum SomeEnum<T,U,V> 来声明 multi-payload 风格的枚举,这样就能正常运行。这用来提示未完成的指令寄存器(IR)引起的错误。

      • 在 Objective-C 的枚举类型导入到 Swift 时,已经废弃的枚举元素将不会影响可用元素的使用,这个可能须要 Swift 中一些枚举名称的改变。

      • 从 C 中导入的枚举类型都表示为 RawRepresentable,这包括哪些没有被声明为 NS_ENUMNS_OPTIONS 枚举值,全部这些枚举类型中的 value 属性都须要重名为 rawValue.

    • 十、方法和函数如今使用一样的参数命名规则了,咱们能够用 “_” 符号来省略一个外部的参数名,为了简化使用,用来指定参数名的简化符号 “#” 被移除,由于 Swift 为默认参数提供了特殊的规则:

      • 声明:

        func printFunction(str:String, newline:Bool)
            func printMethod(str:String, newline:Bool)
            func printFunctionOmitParameterName(str:String, _newline:Bool)
      • 调用:

        printFunction("hello", newline:true)
            printMethod("hello", newline:true)
            printFunctionOmitParameterName("hello", true)
    • 十一、条件循环语句 do/while 循环被重名为 repeat/while。关键字 do 目前用来引入一个新的做用域(这对新引进的错误处理和 defer 关键字很重要)。

      Swift 1.2:
      
              do {
                  ...
              } while <condition>
      
          Swift 2.0:
      
              repeat {
                  ...
              } while <condition>
    • 十二、打印语句的改变,在 Swift1 中,有 println()print() 两个在控制台打印语句的方法,前者是换行打印,后者是连行打印。在 Swift 2 中,println() 已成为过去,取而代之的是他俩的结合体。

      Swift 1.2:
      
              func print(<stuff to print>)
              func println(<stuff to print>)
      
          Swift 2.0:
      
              func print(<stuff to print>, appendNewline:Bool = true)
      
          若是你想作连行打印,如今须要这样写:
      
              print("我要换行!", appendNewline: true)
    • 1三、Swift 的文本注释(doc comments)换成了 Markdown 语法格式,与 Playgrounds 统一(Playgrounds 注释格式源于功能有限的 reStructured Text)。

      参数纵览语法:
      
              ‐ Parameters:
                  ‐ x:...
                  ‐ y:...
      
          单独参数语法:
      
              ‐ parameterx:...
              ‐ parametery:..
      
          返回值:
      
              ‐ returns:...
      
          其余须要在 QuickHelp 中高亮的语法字段,能够参考 Markdown 语法。
    • 1四、在 Swift 中增长了 @objc(propertyName) 属性,当该属性导入到 Objective-C 时能够采用这个 propertyName 做为 getter/setter 访问器的默认名,例如:

      class MyClass:NSObject {
      
              // Objective‐C 属性被命名为 “theProperty”
              @objc(theProperty) property:String
      
              // Objective‐Cgetter 访问器被命名为 “theProperty”
              // Objective‐Csetter 访问器被命名为 “setTheProperty:”
          }
    • 1五、注册通知由

      var types = UIUserNotificationType.Badge | UIUserNotificationType.Sound | UIUserNotificationType.Alert
              var acceptAction = UIMutableUserNotificationAction()
      
              acceptAction.identifier = "ACCEPT_IDENTIFIER"
              acceptAction.title = "Accept"
              acceptAction.activationMode = UIUserNotificationActivationMode.Foreground
              acceptAction.destructive = false
              acceptAction.authenticationRequired = false
      
              var inviteCategory = UIMutableUserNotificationCategory()
      
              inviteCategory.identifier = "INVITE_CATEGORY"
              inviteCategory.setActions([acceptAction], forContext: UIUserNotificationActionContext.Default)
              inviteCategory.setActions([acceptAction], forContext: UIUserNotificationActionContext.Minimal)
      
              var categories = NSSet(object: inviteCategory)
              var mySettings = UIUserNotificationSettings(forTypes: types, categories: categories as Set<NSObject>)
      
              UIApplication.sharedApplication().registerUserNotificationSettings(mySettings)
              UIApplication.sharedApplication().registerForRemoteNotifications()
      
          修改成:
      
              let acceptAction = UIMutableUserNotificationAction()
      
              acceptAction.identifier = "ACCEPT_IDENTIFIER"
              acceptAction.title = "Accept"
              acceptAction.activationMode = UIUserNotificationActivationMode.Foreground
              acceptAction.destructive = false
              acceptAction.authenticationRequired = false
      
              let inviteCategory = UIMutableUserNotificationCategory()
      
              inviteCategory.identifier = "INVITE_CATEGORY"
              inviteCategory.setActions([acceptAction], forContext: UIUserNotificationActionContext.Default)
              inviteCategory.setActions([acceptAction], forContext: UIUserNotificationActionContext.Minimal)
      
              let categories = NSSet(object: inviteCategory) as! Set<UIUserNotificationCategory>
              let mySettings = UIUserNotificationSettings( forTypes: [.Alert, .Badge, .Sound], categories: categories)
      
              UIApplication.sharedApplication().registerUserNotificationSettings(mySettings)
              UIApplication.sharedApplication().registerForRemoteNotifications()
  • 内部的可见性:

    • 这解决了单元测试中的一个较大的难点。之前的作法:

      • Swift 文件包含在 test target 中。如今不一样的模块中有重复的类的定义,出现没法将 “X” 转换为 “X” 这样很是可怕的错误,有时会没法执行特定的测试。

      • 在测试中引入引入主程序(main program)做为一个模块。如今一切都声明为 public,因此对于测试来讲都是可见的,有时候也包括应该声明为 private 的内部细节。

    • 如今能够启用 testability,它就像 C# 中的 InternalsVisibleTo。主应用程序目标模块的内部细节对测试模块可见。

      • 在对应用或框架的测试设置中,启用 testability。
      • 在单元测试中,使用 @testable import { ModuleName }
    • 这将致使测试忽略某些优化行为并保留稍后导入到测试模块中的那些内部符号。官方文档警告说,因为阻止了某些优化,所以这只适用于调试和测试版本。

  • 模式匹配:

    • Switch 语句的模式匹配(pattern matching)语法和 “if let ..., .... where” 语法一直在推广。能够在任何控制流中使用逗号操做符和 where 条件语句。还可使用新的 case 条件语句,例 - 如:if case .Silly(let a) { }。还有一种用于 Optional<T> 的特殊形式:if case let a? = anOptional { }

      • 模式匹配在循环语句中也可使用:for case let thing? in array { }。 这又是值得单独成文的另外一个特性。

      • 类型标注不能用于模式匹配,而须要做为标注声明的一部分:

        • 这意味着,之前的这样的写法:

          • var (a:Int, b:Float) = foo()
        • 须要被重构为:

          • var (a, b):(Int, Float) = foo()
        • 其实这个改动缘由是为了和元组用法相区分。

  • 错误处理:

    • NSError 变成 throw。这不是咱们一向所认识的异常,这是一个使函数提早返回 Result<T, Error> 的操做,单隐藏了全部提早返回的对象,也隐藏了错误解析(error unwrapping)过程等内容。

      let systemAttributes: [NSObject: AnyObject]?
      
          do {
      
              systemAttributes = try NSFileManager.defaultManager()
                                                  .attributesOfFileSystemForPath(documentDirectoryPath.last!)
      
          } catch _ {
      
              systemAttributes = nil
          }
      
          它完美地与 Objective-C 进行互操做,Swift 语言中,将标记为 throws 的方法做为选择器。这是使用 NSError 的方法,
          -(BOOL or nullable type)someMethodTakingParam:(type)param error:(NSError **),
          这种样式会自动引入标记为 throws 的方法。
    • 应该明白的是这并不像 Java 中已经被检查过的异常(checked exception)那样。Swift 语言并不关心异常的类型,或者处理或者不处理。这又是值得单独成文的另外一功能特性。

  • guard 语句块:

    • 显式地声明你要恒成立的条件语句,恒成立时跳过整个 guard 语句。这样作的好处是绑定在 guard 语句的变量在函数的其余部分也可用。这就避免了将全部的东西都围绕一条 if 语句嵌套使用来解析(unwrap)可选类型的变量。执行到函数中 guard 语句中的 else 部分,函数必定会退出并抛出异常。也可能会调用带有 @noreturn 标记的函数。
  • Defer 关键字:

    • 关键字 defer 也很重要,由于它能够取代传统 C 风格的 “if (err) goto cleanup”。得到资源后接着就是 defer { release_resource() }。而后无论函数返回结果如何,得到的资源都将被清理。这也意味着资源的释放紧随获取资源以后。这看起来不起眼儿,实则很重要。
  • NS_OPTIONS 和 OptionSetType:

    • NS_OPTIONS 类型如今遵循 OptionSetType 协议,这样能够避免 set 样式的接口调用。位操做枚举(bitwise enumeration)与数组风格的语法相结合,而不使用管道符 “ | ” 按位操做,而且具备全部范围的集合操做功能。检查一下是否具备 contains 功能的标志,或可以执行像 isSubsetOfisDisjointWith 等这样集合操做的其余功能。这是显著的改进,表达了不直接对位进行操做的意愿。

    • 避免采用以下位运算的调用方式:

      // Swift1.2:
      
              object.invokeMethodWithOptions(.OptionA | .OptionB)
              object.invokeMethodWithOptions(nil)
      
              if options & .OptionC == .OptionC {
      
                  //.OptionC 被设置
              }
    • 选项设置支持字面量语法和 set 样式的调用,如 contains:

      object.invokeMethodWithOptions([.OptionA, .OptionB])
          object.invokeMethodWithOptions([])
      
          if options.contains(.OptionC) {
      
              //.OptionC is set
          }
    • 这种变化意味着位操做枚举实际上再也不是枚举了。将这些位操做枚举声明为结构体,实现 OptionSetType 协议,提供 rawValue 属性。而且建立值做为结构体的静态成员。Swift 便会搞定其他的一切,自动提供全部集合的操做。

    • 在 Swift 中一个新的 Option 设置类型能够采用结构体遵循 OptionSetType 协议的方式编写。若是该类型中指定了一个 rawValue 属性和 static let 的常量定义,那么标准库将会为其余选项提供默认实现:

      structMyOptions:OptionSetType {
      
          let rawValue:Int
              static let TuringMachine = MyOptions(rawValue:1)
              static let LambdaCalculus = MyOptions(rawValue:2)
              static let VonNeumann = MyOptions(rawValue:4)
          }
      
          let churchTuring:MyOptions = [.TuringMachine, .LambdaCalculus]
  • 协议扩展:

    • 在 Swift 1.0 时代,协议(Protocol)基本上相似一个接口,定义若干属性和方法,供类、结构体、枚举遵循和实现。在 Swift 2.0 中,能够对协议进行属性或者方法的扩展,和扩展类与结构体相似。,包括与类型约束有关的通用协议。还能够本身提供协议的默认实现。这让咱们开启了面向协议编程的篇章。先前,你不能,你说:“我要使用方法 X 来扩展 CollectionType,但只有集合中的类型知足某些条件才能够”。如今,你能够这么作,而且不少像 map,filter 和 sort 这样的全局函数已经进行了扩展。这样就解决了不少痛点,这也是值得单独成文的内容。同时,要看看 WWDC 的面向协议编程(Protocol Oriented Programming)了解一些细节。

    • Swift 中,大多数基础对象都遵循了 CustomStringConvertible 协议,好比 Array、Dictionary(Swift 1.0 中的 Printable 协议),该协议定义了 description 方法,用于 print 方法打印对象。如今咱们对该协议扩展一个方法,让其打印出大写的内容:

      var arr = ["hello", "world"]
      
          print(arr.description)         // "[hello, world]"
      
          extension CustomStringConvertible {
              var upperDescription: String {
                  return "\(self.description.uppercaseString)"
              }
          }
      
          print(arr.upperDescription)    // "[HELLO, WORLD]"
    • 若是在 Swfit 1.0 时代,要想达到上述示例的效果,那么咱们须要分别对 Array、Dictionary 进行扩展,因此协议的扩展极大的提升了咱们的编程效率,也一样使代码更简洁和易读。

  • available 检查:

    • 做为 iOS 开发者,谁都但愿使用最新版本 iOS 的 Api 进行开发,省事省力。但经常事与愿违,由于咱们常常须要适配老版本的 iOS,这就会面临一个问题,一些新特性特性或一些类没法在老版本的 iOS 中使用,因此在编码过程当中常常会对 iOS 的版本作以判断,就像这样:

      if NSClassFromString("NSURLQueryItem") != nil {
              // iOS 8 或更高版本
          } else{
              // iOS8 以前的版本
          }
    • 以上这只是一种方式,在 Swift 2.0 以前也没有一个标准的模式或机制帮助开发者判断 iOS 版本,并且容易出现疏漏。在 Swift 2.0 到来后,咱们有了标准的方式来作这个工做:

      if #available(iOS 8, *) {
      
              // iOS 8 或更高版本
              let queryItem = NSURLQueryItem()
      
          } else {
              // iOS8 以前的版本
          }
    • @available 属性自 Swift 1.2 就存在了而且后续支持得很好。添加了一个新的陌生语法 if #available(),为处理版本检查提供了支持。而不是插入你喜欢的方法。

    • 遗憾的是你不能只声明一个属性 UISearchController 并将 target 设置为 iOS 7,而后只容许访问类中的属性。Swift 但愿整个类的定义均可以或者不能够。也能够再也不采用协议,除非支持 target设置中全部的操做系统版本,除非将整个类标记为只在更新的操做系统版本可用。

    • 这意味着使用 if #available() 存在单独的子类和对建立适当对象的保护。尽管如此,我我的仍是发现了一个 Bug,应用在 iOS 4.0-4.1 发生崩溃,因为编译器没有发出警告,方法只在 iOS 4.2 才引入,所以我犹如与定时炸弹相伴。

  • C 函数指针:

    • Swift 如今可使用 C 函数指针,CFunctionPointer<T -> U> 类型被移除,C 函数如今使用新的 @convention(c) 属性声明,和其余函数类型同样,@convention(c) T -> U 是一个非空的除非是它是可选的。任何全局函数,嵌套函数和不捕获状态的闭包均可以做为一个 C 函数指针直接传递。你也能够调用来自 C 程序的函数。

    • 你能够显示地使用新属性 @convention(c),表示函数应该使用 C 调用约定,简单痛快!尽管我想不出在此对块(block)的支持有何用,做为所发生变化的一部分,@objc_block 也被删掉了,使用 @convention(block) 取而代之。@convention(swift) 默认支持全部函数和闭包。

  • API 审计:

    • 大量的 API 已经进一步进行了审计而更合理。举几个例子:

      • UITableView 的 dequeueReusableCellWithIdentifier 方法如今返回 UITableViewCell? 类型的对象。

      • UIKit 的属性如今也被声明为了实际的属性。

      • translatesAutoresizingMaskToConstraints = false 代替了 setTranslatesAutoresizingMaskToConstrains(false)

  • 库:

    • 这并非编程语言所特有的。iOS 9 含有不一样版本的 Swift 标准库,而且在将来系统中将添加修正后的 Swift 标准库。结合新的 App Thining 技术,下载过程当中苹果商店会将 Swift 标准库剥离出去的。我仍然在追根溯源地探求这到底是如何工做的。
  • 遗漏:

    • 明显的一个遗漏是处理异步代码。苹果公司为咱们提供了 GCD,这是一个强大的基础类库,能够构建不少异步操做和并发原语。然而,这些天咱们作的每件事,构建用户接口和 API 都须要考虑异步性和并发性。咱们把一个文件读操做锁定一段时间,对用户来讲整个世界就都静止了。这是个持续的痛点,不是多大的事儿,但若是常常性地天天重复,恐怕也是不行的。C# 和 JavaScript 都采用了 async/await 来为异步代码提供一流的语言支持。我想不少人都想知道,Swift 会提供什么样的语法糖来帮助咱们在实现异步操做方面确保正确性。

二、Swift 2.2 新特性

  • 容许更多的关键字用作参数名:

    • 好的参数名对于提升代码可读性很重要。在 Swift 中不少关键字好比 in,repeat,defer 都不能用作参数名。2.2 中,除了少数修饰参数的关键字外都将容许用做参数名。

      swiftnew1

  • 为 Tuples 增长对比操做符:

    • 当前,Tuples 的数据不能使用 == 操做符,2.2 中将支持 Tuples。

      swiftnew2

  • 关联已存在类型时,再也不使用 typealias:

    • typealias 如今有两个用处:
      • 为一个已经存在的类型取个别名
      • 在协议中做为一个类型的占位名称
    • 代码以下:

      swiftnew3

    • 这是两种彻底不一样的用法,不该该用同样的关键字。2.2 中将第一种状况时,启用新的关键字 associatedtype

  • 函数签名将包括参数名:

    • 一个函数有相同的函数名,参数名不一样有多个重载很常见。当有多个重载时,在调用时可以经过参数名来区别。可是在获取类型时,却不包括参数名。

    • 举例 UIView 中有这么几个方法:

      swiftnew4

    • 使用时能够经过参数名区分:

      swiftnew5

    • 可是这样使用时却会报错,2.2 中将会解决这个问题。

      • let fn = someView.insertSubview // ambiguous: could be any of the three methods
  • 一个新的方法生成 selector:

    • 如今为了生成 OC 下使用的 selector 只能使用字符串生成,没有类型检查,很容易形成失误。将提供一个 #selector() 方法生成 selector,以下:

    • let sel = #selector(UIView.insertSubview(_:at:)) // produces the Selector "insertSubview:atIndex:" 增长 #if swift 语法判断当前 swift 版本

    • 使用以下:

      swiftnew6

相关文章
相关标签/搜索