美文网首页iOS开发IOS
WWDC2015 -- What's New in Sw

WWDC2015 -- What's New in Sw

作者: 嘻嘻zhy | 来源:发表于2016-02-23 18:20 被阅读103次

    标签(空格分隔): WWDC


    Swift2的目标

    1. 希望Swift语言核心的特性和行为以及它的工具变好。
    2. 编写优秀的和安全的代码
    3. 富有表现力的库与API

    五个在Swift中新特性

    1. Fundamentals
    2. Pattern Matching
    3. Availability Checking
    4. Protocal Extensions
    5. Error Handling

    Fundamentals

    enum  Animals{
    case Dog,Car,Dragon
    }
    let a = Animals.Dragon
    print(a)
    

    枚举携带更多信息,而且可以打印出来。


    enum Either<T1,T2>{
    case First(T1)
    case Second(T2)
    }
    

    可以用相关值关联方式创建数组。


    enum Tree<T> {
      case Leaf(T)
    indirect case Node(Tree, Tree) 
    }
    
    

    递归支持。


    do {
      ...
      ...
    }while()
    
    repeat {
      let a = Animals.Troll
      ...
    }while()
    
    

    用repeat-while代替了do-while,从字面上意义更加明确。也避免与异常处理混淆。


    Swift 1:

       viewAnimationOptions = .Repeat | .CurveEaseIn | .TransitionCurlUp
       viewAnimationOptions = nil
       if viewAnimationOptions & .TransitionCurlUp != nil {
    

    Swift2:

       viewAnimationOptions = [.Repeat, .CurveEaseIn, .TransitionCurlUp]
       viewAnimationOptions = []
       if viewAnimationOptions.contains(.TransitionCurlUp) {
    

    对于选项设置,用集合代替了位操作符。变得简单又强大。


    struct MyFontStyle : OptionSetType {
        let rawValue : Int
        static let Bold = MyFontStyle(rawValue: 1)
        static let Italic = MyFontStyle(rawValue: 2)
        static let Underline  = MyFontStyle(rawValue: 4)
        static let Strikethrough = MyFontStyle(rawValue: 8)
    }
    var myFont :MyFontStyle = MyFontStyle()
    myFont = []
    myFont = [.Underline]
    myFont = [.Bold, .Italic]
    if myFont.contains(.Strikethrough) {
    }
    

    注意这里的rawValue为数值相加。


    func save(name: String, encrypt: Bool) { ... }
    
    class Widget {
    func save(name: String, encrypt: Bool) { ... } 
    ···
    }
    save("thing", encrypt: false)
    widget.save("thing", encrypt: false)
    

    将方法与函数统一为单一的函数声明。
    统一了函数参数标签。


    func save(name: String, encrypt: Bool) {  }
    save("123", encrypt: false)
    
    func save(name name: String, encrypt: Bool) {  }
    save(name: "123", encrypt: true)
    
    func save(name: String, _ encrypt: Bool) {  }
    save("123", true)
    

    命名方式对使用方式的影响。


    struct MyCoordinates {
        var points : [CGPoint]
        func updatePoint() {
            points[42].x = 19
        }
    }
    

    编译器更新,能够对以前不能识别的错误进行诊断。


    
    var abc= ···
    
    let size = abc 
    
    var indices = abc
    indices.sort()
    

    对三种情况进行提示。

    • 不会被修改的变量使用了var提示使用let。
    • 从来没有被使用的变量。
    • 方法的返回值没有被使用。

    //SDK Improvements
    
    class func requestHeaderFieldsWithCookies(cookies: [AnyObject]!)
         -> [NSObject : AnyObject]!
         
    //现在为
    class func requestHeaderFieldsWithCookies(cookies: [AnyObject] )
         -> [NSObject : AnyObject]
         
    //使用时
    class func requestHeaderFieldsWithCookies(cookies: [NSHTTPCookie]) 
    -> [String: String] 
    

    采纳了新的特性与更好的规则:

    • Nullability修饰。
    • Objective-C 类型集合。
    • NS_ENUM, NS_OPTIONS, instancetype, @property, etc。

     @testable
     import MyApp
    

    Swift1中如果需要测试,需要将内容设置为public,但其实很多内容不应该被public。现在在测试中这么写,就能解决问题。


    /**:
     
     ##可以使用MarkDown方式进行注释
     
     ####真的可以
     
     - 1
     - 2
     - 3
      
     >print("Hello World")
      
     */
    class Hello {
    }
    
    

    可以用MarkDown的方式进行注释。这是一个伟大的,著名的,非常受欢迎,可爱的语法。


    可以将Swift1自动转化为Swift2


    Pattern Matching

    func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if let dest = segue.destinationViewController as? BlogViewController
    ...
        } 
    }
    

    if-let 语句使用。

    func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if let dest = segue.destinationViewController as? BlogViewController{
    if let blogIndex = tableView.indexPathForSelectedRow()?.row { if segue.identifier == blogSegueIdentifier {
                    dest.blogName = swiftBlogs[blogIndex]
                    ...
                    ...
                 }
            }
        }
    }
    
    

    如果嵌套太多会对结构产生如同金字塔一样的灾难。

    func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if let dest = segue.destinationViewController as? BlogViewController
    if let blogIndex = tableView.indexPathForSelectedRow()?.row { if segue.identifier == blogSegueIdentifier {
                    dest.blogName = swiftBlogs[blogIndex]
                    ...
                    ...
                } 
            }
        }
    }
    

    在swift1.2中引入复合条件语句,这使得代码显得比较自然。
    可以检查多个自选和布尔条件合适的嵌入。虽然比之前好但是这并没有解决早期存在的问题。

    
    func process(json: AnyObject) -> Either<Person,String> {
        guard let name = json["name"] as? String else {
            return .Second("missing name")
        }
         guard let year = json["year"] as? Int else{
            return .Second("missing year")
        }
        let person = processPerson(name, year)
        return .First(person)
    }
    
    //可以合并书写
    func process(json: AnyObject) -> Either<Person,String> {
        guard let name = json["name"] as? String,
              let year = json["year"] as? Int else {
            return .Second(“bad input”)
        }
        let person = processPerson(name, year)
        return .First(person)
    }
    
    

    引入了新的Guard语句,使用Guard-else,将许多工作在Guard语句中声明,同时检查多个语句,更加简洁,也是更好提前结束的方式。


    enum Animals{
        
        
        case Dog(Int) ,Car(String),Dragon(Float)
    }
    
    func myDog()->Animals
    {
        return Animals.Dog(5)
    }
    switch Dog() {
    case .Dog(let value)  where value != 42:
        print(value)
    ······
    default: break
        
    }
    //可以只对一个条件判断
    if case .Dog(let value) = myDog() where value != 42 {
        print(value)
    }
    

    使用switch的时候我们需要详细的描述各种条件,但是如果只需要等于一种case进行判断,可以缩写。


    //以前的方式
    for value in mySequence {
        if value != "" {
            doThing(value)
        }
    }
    //新的方式1
    for value in mySequence where value != "" {
        doThing(value)
    }
    //新的方式2
    for case .MyEnumCase(let value) in enumValues {
        doThing(value)
    }
    
    

    为了快速的循环做了两件事。

    1. 加入内联能力。
    2. 更强大的条件匹配。

    API Availability Checking

    • 在不抛弃用户的情况下利用新的能力
    • 简单而且丰富的检查
    • 通过语言静态的实现
    @IBOutlet var dropButton: NSButton!
    override func awakeFromNib() {
      dropButton.springLoaded = true
    }
    

    springLoaded这个API是在MAC OS 10.10.3中后出现,如果程序中这么写,如果使用的系统环境低于10.10.3就会出错。

    @IBOutlet var dropButton: NSButton!
    override func awakeFromNib() {
      if dropButton.respondsToSelector("setSpringLoaded") {
          dropButton.springLoaded = true
      }
    }
    

    用respondsToSelector去检查方法是一种很常见的解决方式,但是这种方式并不够好,是棘手的、容易出错的模式。比如我忘记方法的名称或者拼写错误。

    error: springLoaded is only available on Mac OS X 10.10.3 or later

    在Swift2中,编译器会更具你的minimum deployment target去判断是否能够使用所有的API。上面就是判断的结果。

    @IBOutlet var dropButton: NSButton!
    override func awakeFromNib() {
        if #available(OSX 10.10.3, *) {
            dropButton.springLoaded = true
        }
    }
    

    加入了新的#available判断条件,可以直接根据运行环境判断是否使用。


    Protocal Extensions

    • 在标准库中更多持久化的方法使用
    • 新的有效的设计模式
    extension Array{
    func countIf(match: Element ->Bool) -> Int {
            var n = 0
            for value in self {
                if match(value) { n++ }
            }
            return n
        }
    }
    

    扩展是一个非常强大的功能,迅速。可以采取任意类型的数组,并添加我自己的方法。当我添加一个扩展,我真的增加了新的功能,感觉只是作为第一类,只是作为核心的类型的任何类型的设计师可能已经添加了。

    
    func countIf(match: <CollectionType>){collection:T,match: T.Generator.Element->Bool) -> Int {
        var n = 0
        for value in self {
            if match(value) { n++ }
        }
    return n }
    
    

    该方法是一个全局函数。

    1. 这是一个额外的语法,可能会被忽略使用。
    2. 在Array方法实现时并不会显示在数组中的任何功能列表中。
    extension CollectionType {
    func countIf(match: Element -> Bool) -> Int {
            var n = 0
            for value in self {
                if match(value) { n++ }
            }
    return n }
    }
    

    在Swift2中,我们可以直接对协议进行扩展,这样所有支持协议的类都能使用该方法。


    let numbers = [1,2,3,4]
    
    //swift1
    let x = filter(map(numbers) { $0 * 3 }) { $0 >= 0 }
    
    //swift2
    let x = numbers.map { $0 * 3 }.filter { $0 >= 0 }
    
    

    全局的泛型方法变为函数。

    Error Handling

    在Swift上很很大提升空间的地方

    • 安全性
    • 可读性
    • 编写性

    共同的问题

    • 太容易忽视错误
    • 重复的,有错误倾向的模式
    • 很难去思考隐晦的行为

    错误的种类

    • 琐碎的小错误
    • 逻辑错误
    • 可以被知道细节可以被发现的错误
    func preflight() {
        url.checkResourceIsReachable()
        resetState()
    }
    

    这个方法中url.checkResourceIsReachable()可能会失败。如果使用NSError呢会怎样?

    func preflight(inout error: NSError?) -> Bool {
        if url.checkResourceIsReachableAndReturnError(&error) {
            return false
        }
        resetState()
        return true
    }
    

    原本只有两行简单的代码现在拓展了很多内容,有了if语句的嵌套,并且有许多格外的参数。
    在没有编译器帮助的情况下,手动操作加上返回条件。
    只能在返回false的时候会发生错误,而我只是想知道错误的方式。

    显然checkResourceIsReachableAndReturnError能出错。
    显然preflight方法能够出错。
    所有的控制流都清晰。(并不需要知道所有的情况)

    func preflight() throws {
        try url.checkResourceIsReachable()
        resetState()
    }
    
    
    1. 在可能出错的语句前加上try。
    2. 抛出异常,但没有处理异常。
      如果需要处理异常呢?
    func preflight() -> Bool {
        do {
            try url.checkResourceIsReachable()
            resetState()
            return true
        } catch let error {
            return false
        } 
    }
    

    使用do-catch语句处理,将错误储存为error。

    
    func preflight() -> Bool {
        do {
            try url.checkResourceIsReachable()
            resetState()
            return true
        } catch NSURLError.FileDoesNotExist {
            return true
        } catch let error {
            return false
        } 
    }
    

    可以对于指定的错误进行处理。

    
    func preflight() {
        try! url.checkResourceIsReachable()
        resetState()
    }
    

    如果遇到很严重的致命错误,抛出后程序会崩溃,可以使用try!,这样虽然进行了处理实际上没有抛出错误。


    ErrorType is a protocol in the Swift standard library
    我们能够用枚举创建自己的错误类型准守协议

    enum DataError : ErrorType {
        case MissingName
        case MissingYear
        // add more later
    }
    
    func processPerson(json: AnyObject) -> Either<Person,String> {
      guard let name = json["name"] as? String {
        return .Second("missing name")
      }
      guard let year = json["year"] as? Int {
        return .Second("missing year")
    }
      return .First(Person(name, year))
    }
    

    可以改为

    func processPerson(json: AnyObject) -> Either<Person,String> {
      guard let name = json["name"] as? String {
        throw DataError.MissingName
      }
      guard let year = json["year"] as? Int {
        throw DataError.MissingYear
    }
      return .First(Person(name, year))
    }
    

    并且修改返回值,因为不需要再使用Either了。

    func processPerson(json: AnyObject) throws -> Person {
      guard let name = json["name"] as? String {
        throw DataError.MissingName
      }
      guard let year = json["year"] as? Int {
        throw DataError.MissingYear
    }
      return Person(name, year)
    }
    

    
    func processSale(json: AnyObject) throws {
      delegate?.didBeginReadingSale()
      guard let buyerJSON = json["buyer"] as? NSDictionary {
        throw DataError.MissingBuyer
      }
      let buyer = try processPerson(buyerJSON)
      guard let price = json["price"] as? Int {
        throw DataError.MissingPrice
      }
      delegate?.didEndReadingSale()
      return Sale(buyer, price)
    }
    

    我在这个方法中我需要加上个代理,在开始与结束的时候处理。
    但是如果出现错误以及异常,会在delegate?.didEndReadingSale()执行之前就需要跳出。

    func processSale(json: AnyObject) throws {
      delegate?.didBeginReadingSale()
      guard let buyerJSON = json["buyer"] as? NSDictionary {
        delegate?.didEndReadingSale()
        throw DataError.MissingBuyer
      }
      let buyer : Person
      do {
    buyer = try processPerson(buyerJSON) } catch { 
        delegate?.didEndReadingSale()
    throw error }
      guard let price = json["price"] as? Int {
        delegate?.didEndReadingSale()
     throw DataError.MissingPrice
       return Sale(buyer, price)
    }
    

    需要在每一个跳出方法的地方添加上delegate。
    繁琐而且容易出错。

    func processSale(json: AnyObject) throws {
      delegate?.didBeginReadingSale()
      defer { delegate?.didEndReadingSale() }
      guard let buyerJSON = json["buyer"] as? NSDictionary {
        throw DataError.MissingBuyer
      }
      let buyer = try processPerson(buyerJSON)
      guard let price = json["price"] as? Int {
        throw DataError.MissingPrice
      }
      return Sale(buyer, price)
    }
    

    这时候我们只需要将需要执行的代码放入defer中,只要在方法结束时就会自动触发defer执行。


    『Exception handling』schemes

    • 任何都能被抛出。
    • 性能与异常非常相关,并且成反比。

    Swift的错误处理更加平衡

    • Not table-based unwinding。
    • 与if判断语句的性能相近。

    Swift用Cocoa API的错误处理设计非常优雅。
    能够自动识别在Cocoa中常见的约定。

    //Swift1
    extension NSIncrementalStore {
    func loadMetadata(error: NSErrorPointer) -> Bool
    }
    //Swift 2:
     extension NSIncrementalStore {
       func loadMetadata() throws
    }
    
    //Swift 1:
    extension NSData {
    class func bookmarkDataWithContentsOfURL(bookmarkFileURL: NSURL, 
    -> NSData? }
    //Swift 2:
    extension NSData {
    class func bookmarkDataWithContentsOfURL(bookmarkFileURL: NSURL) throws
    -> NSData }
    

    例如,方法有一个NSError参数并返回bool类型。
    自动添加throw方法并取消bool返回值。
    同样,如果它返回一个可选的结果,我们认识到,返回值为零表示无效的东西,它不再返回一个可选的结果,归入错误处理。
    正是在这2个非常简单的规则,我们发现绝大多数的在系统中的API与新的Swift错误处理模型结合变得【无缝】而且【美观】,我们认为在Swift中这是一个伟大的新的方式来处理错误。

    相关文章

      网友评论

        本文标题:WWDC2015 -- What's New in Sw

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