swift4.2 - CSDN
  • Swift 4.2 新特性(译)

    2018-11-09 17:53:17
    Swift 4.2 新特性(译) 一、概述二、准备三、语言演进3.1 随机数生成3.2 动态成员查找3.3 枚举实例集合3.4 新的序列方法3.5 检测序列元素3.6 条件遵守更新3.7 Hashable 增强3.8 集合中移除元素3.9 更改布尔值3.10 ...

    一、概述

    Swift 4.2 在 Xcode 10 beta 版上可以使用了,在 Swift 4.1 的基础上更新了很多语言特性,为 Swift 5 中 ABI 稳定做好准备。

    这篇文章包含了 Swift 4.2 中的重大的改变。因为 Swift 4.2 需要 Xcode 10,所以请下载安装最新的 Xcode 测试版本。

    二、准备

    Swift 4.2 和 Swift 4.1 源码兼容,但是和其他发布版本的二进制不兼容。Swift 4.2 是 Swift 5 实现 ABI 稳定(不同的 Swift 版本编译的应用程序和库之间实现兼容)的一个中间阶段。ABI 的特性在集成进最终的 ABI 之前会接收社区的大量反馈。

    三、语言演进

    在这个版本中有很多新的语言特性。例如,随机数生成,动态成员查找等等

    3.1 随机数生成

    3.1.1 随机数生成
    arc4random_uniform(_: ) 返回一个 0 - 9 之间的随机数字。这种实现方式有两个问题:

    • 需要引入 Foundation 框架,在 Linux 下无法工作。
    • Linux上的随机数生成会产生模偏差(有取模的过程,更容易随机到小的数)。
    // Swift 4.1
    let digit = Int(arc4random_uniform(10))
    

    Swift 4.2 在标准库中添加了随机数的 API SE-0202

    /// Swift 4.2
    // 1  
    let digit = Int.random(in: 0..<10)// 2
    if let anotherDigit = (0..<10).randomElement() {
     print(anotherDigit)
    } else {
     print("Empty range.")
    }// 3
    let double = Double.random(in: 0..<1)
    let float = Float.random(in: 0..<1)
    let cgFloat = CGFloat.random(in: 0..<1)
    let bool = Bool.random()
    

    注:randomElement() 如果 range 是空,返回 nil

    3.1.2 数组随机

    Swift 4.1 数组随机也是采用 C 函数的形式,这种方式会存在上面提到的问题,而且会存在 Int 和 Int32 转换的问题。

    /// swift 4.1
    let playlist = ["Nothing Else Matters", "Stairway to Heaven", "I Want to Break Free", "Yesterday"]
    let index = Int(arc4random_uniform(UInt32(playlist.count)))
    let song = playlist[index]
    

    Swift 4.2 采用了更加简单直接的方式。

    /// swift 4.2
    if let song = playlist.randomElement() {
     print(song)
    } else {
     print("Empty playlist.")
    }
    

    3.1.3 洗牌算法
    Swift 4.1 不包含任何集合的洗牌算法,所以要采用比较曲折的方式来实现。

    // 1
    let shuffledPlaylist = playlist.sorted{ _, _ in arc4random_uniform(2) == 0 }
    
    // 2
    var names = ["Cosmin", "Oana", "Sclip", "Nori"]
    names.sort { _, _ in arc4random_uniform(2) == 0 }
    

    Swift 4.2 提供了更加高效更加优雅的实现 Shuffling Algorithms

    let shuffledPlaylist = playlist.shuffled()
    names.shuffle()
    

    注:使用 shuffled() 来创建一个洗牌后的数组。使用 shuffle() 来将数组洗牌。

    3.2 动态成员查找

    Swift 4.1 使用下面的方式实现自定义下标操作。

    /// swift 4.1
    class Person {
      let name: String
      let age: Int
      private let details: [String: String]
      
      init(name: String, age: Int, details: [String: String]) {
        self.name = name
        self.age = age
        self.details = details
      }
      
      subscript(key: String) -> String {
        switch key {
          case "info":
            return "\(name) is \(age) years old."
          default:
            return details[key] ?? ""
        }
      }
    }
    
    let details = ["title": "Author", "instrument": "Guitar"]
    let me = Person(name: "Cosmin", age: 32, details: details)
    me["info"]   // "Cosmin is 32 years old."
    me["title"]  // "Author"
    

    Swift 4.2 使用动态成员查找来提供点语法来实现下标调用 Dynamic Member Lookup

    /// swift 4.2
    // 1
    @dynamicMemberLookup
    class Person {
      let name: String
      let age: Int
      private let details: [String: String]
      
      init(name: String, age: Int, details: [String: String]) {
        self.name = name
        self.age = age
        self.details = details
      }
      
      // 2
      subscript(dynamicMember key: String) -> String {
        switch key {
          case "info":
            return "\(name) is \(age) years old."
          default:
            return details[key] ?? ""
        }
      }
    }
    
    // 3
    me.info   // "Cosmin is 32 years old." 
    me.title  // "Author"
    

    使用步骤:

    • 标记 Person 为 @dynamicMemberLookup 使下标可以使用点语法
    • 遵守 @dynamicMemberLookup 实现 subscript(dynamicMember:) 方法
    • 使用点语法调用之前定义的下标

    注:编译器会在运行时动态评估下标的调用,这样就可以写出像 Python 或者 Ruby 等脚本语言一样类型安全的代码。

    动态成员查找不会和类的属性混淆。

    me.name // "Cosmin"
    me.age // 32
    

    可以使用点语法而非下标来调用 name 和 age。而且派生类可以继承基类的动态成员查找。

    @dynamicMemberLookup
    class Vehicle {
      let brand: String
      let year: Int
      
      init(brand: String, year: Int) {
        self.brand = brand
        self.year = year
      }
      
      subscript(dynamicMember key: String) -> String {
        return "\(brand) made in \(year)."
      }
    }
    
    class Car: Vehicle {}
    
    let car = Car(brand: "BMW", year: 2018)
    car.info  // "BMW made in 2018."
    

    可以通过协议拓展给已有类型添加动态成员查找

    // 1
    @dynamicMemberLookup
    protocol Random {}
    
    // 2
    extension Random {
      subscript(dynamicMember key: String) -> Int {
        return Int.random(in: 0..<10)
      }
    }
    
    // 3
    extension Int: Random {}
    
    // 4
    let number = 10
    let randomDigit = String(number.digit)
    let noRandomDigit = String(number).filter { String($0) != randomDigit }
    

    3.3 枚举实例集合

    Swift 4.1 默认没有提供访问枚举实例集合的方式,所以实现方式不是很优雅。

    enum Seasons: String {
      case spring = "Spring", summer = "Summer", autumn = "Autumn", winter = "Winter"
    }
    
    enum SeasonType {
      case equinox
      case solstice
    }
    
    let seasons = [Seasons.spring, .summer, .autumn, .winter]
    for (index, season) in seasons.enumerated() {
      let seasonType = index % 2 == 0 ? SeasonType.equinox : .solstice
      print("\(season.rawValue) \(seasonType).")
    }
    

    为了解决这个问题,Swift 4.2 给枚举类型添加了实例数组。

    // 1
    enum Seasons: String, CaseIterable {
      case spring = "Spring", summer = "Summer", autumn = "Autumn", winter = "Winter"
    }
    
    enum SeasonType {
      case equinox
      case solstice
    }
    
    // 2
    for (index, season) in Seasons.allCases.enumerated() {
      let seasonType = index % 2 == 0 ? SeasonType.equinox : .solstice
      print("\(season.rawValue) \(seasonType).")
    }
    

    如果枚举中包含 unavailable,需要将availablecase手动维护协议中的 allCases

    enum Days: CaseIterable {
      case monday, tuesday, wednesday, thursday, friday
      
      @available(*, unavailable)
      case saturday, sunday
      
      static var allCases: [Days] {
        return [.monday, .tuesday, .wednesday, .thursday, .friday]
      }
    }
    

    allCases 中只能添加 weekdays,因为 saturdaysunday 被标记为各个平台不可用。

    枚举实例数组中也可以添加有关联值的实例。

    enum BlogPost: CaseIterable {
      case article
      case tutorial(updated: Bool)
      
      static var allCases: [BlogPost] {
        return [.article, .tutorial(updated: true), .tutorial(updated: false)]
      }
    }
    

    3.4 新的序列方法

    Swift 4.1 中的 Sequence 定义了查找指定元素的第一个索引位置或者满足指定条件的第一个元素的方法。

    /// swift 4.1
    let ages = ["ten", "twelve", "thirteen", "nineteen", "eighteen", "seventeen", "fourteen",  "eighteen", "fifteen", "sixteen", "eleven"]
    
    if let firstTeen = ages.first(where: { $0.hasSuffix("teen") }), 
       let firstIndex = ages.index(where: { $0.hasSuffix("teen") }), 
       let firstMajorIndex = ages.index(of: "eighteen") {
      print("Teenager number \(firstIndex + 1) is \(firstTeen) years old.")
      print("Teenager number \(firstMajorIndex + 1) isn't a minor anymore.")
    } else {
      print("No teenagers around here.")
    }
    

    Swift 4.2 为了实现一致性重构了方法名

    /// swift 4.2
    if let firstTeen = ages.first(where: { $0.hasSuffix("teen") }), 
       let firstIndex = ages.firstIndex(where: { $0.hasSuffix("teen") }), 
       let firstMajorIndex = ages.firstIndex(of:  "eighteen") {
      print("Teenager number \(firstIndex + 1) is \(firstTeen) years old.")
      print("Teenager number \(firstMajorIndex + 1) isn't a minor anymore.")
    } else {
      print("No teenagers around here.")
    }
    

    Swift 4.1 也没有定义查找指定元素的最后一个索引的位置和满足指定条件的的最后一个元素等方法。在 Swift 4.1 中我们可能采用下面的方法来处理。

    /// swift 4.1
    // 1
    let reversedAges = ages.reversed()
    
    // 2
    if let lastTeen = reversedAges.first(where: { $0.hasSuffix("teen") }), 
       let lastIndex = reversedAges.index(where: { $0.hasSuffix("teen") })?.base, 
       let lastMajorIndex = reversedAges.index(of: "eighteen")?.base {
      print("Teenager number \(lastIndex) is \(lastTeen) years old.")
      print("Teenager number \(lastMajorIndex) isn't a minor anymore.")
    } else {
      print("No teenagers around here.")
    }
    
    

    Swift 4.2 添加了相应的方法,使用方式如下

    if let lastTeen = ages.last(where: { $0.hasSuffix("teen") }), 
       let lastIndex = ages.lastIndex(where: { $0.hasSuffix("teen") }), 
       let lastMajorIndex = ages.lastIndex(of: "eighteen") {
      print("Teenager number \(lastIndex + 1) is \(lastTeen) years old.")
      print("Teenager number \(lastMajorIndex + 1) isn't a minor anymore.")
    } else {
      print("No teenagers around here.")
    }
    
    

    3.5 检测序列元素

    Swift 4.1 中没有检查序列中所有元素是否满足某个指定条件的方法。不过你可以实现你自己的方法,例如下面检测集合中的元素是否都是偶数。

    let values = [10, 8, 12, 20]
    let allEven = !values.contains { $0 % 2 == 1 }
    

    Swift 4.2 添加了新的方法,很好的简化了代码,提升了可读性。

    let allEven = values.allSatisfy { $0 % 2 == 0 }
    

    3.6 条件遵守更新

    Swift 4.2 给拓展和标准库中添加一些条件遵守方面的改进。

    3.6.1 拓展中的条件遵守

    Swift 4.1 不能在拓展中自动合成 Equatable 的协议实现。例子如下:

    // 1
    struct Tutorial : Equatable {
      let title: String
      let author: String
    }
    
    // 2
    struct Screencast<Tutorial> {
      let author: String
      let tutorial: Tutorial
    }
    
    // 3 
    extension Screencast: Equatable where Tutorial: Equatable {
      // 必须自己实现 == 方法,Swift 4.1 不会自动合成
      static func ==(lhs: Screencast, rhs: Screencast) -> Bool {
        return lhs.author == rhs.author && lhs.tutorial == rhs.tutorial
      }
    }
    
    // 4
    let swift41Tutorial = Tutorial(title: "What's New in Swift 4.1?", author: "Cosmin Pupăză")
    let swift42Tutorial = Tutorial(title: "What's New In Swift 4.2?", author: "Cosmin Pupăză")
    let swift41Screencast = Screencast(author: "Jessy Catterwaul", tutorial: swift41Tutorial)
    let swift42Screencast = Screencast(author: "Jessy Catterwaul", tutorial: swift42Tutorial)
    let sameScreencast = swift41Screencast == swift42Screencast
    

    Swift 4.2 只需要遵守协议,不需要实现。因为编译器会添加一个默认的Equatable协议实现。

    extension Screencast: Equatable where Tutorial: Equatable {}
    

    这个特性也同样支持 HashableCodable

    // 1
    struct Tutorial: Hashable, Codable {
      let title: String
      let author: String
    }
    
    struct Screencast<Tutorial> {
      let author: String
      let tutorial: Tutorial
    }
    
    // 2
    extension Screencast: Hashable where Tutorial: Hashable {}
    extension Screencast: Codable where Tutorial: Codable {}
    
    // 3
    let screencastsSet: Set = [swift41Screencast, swift42Screencast]
    let screencastsDictionary = [swift41Screencast: "Swift 4.1", swift42Screencast: "Swift 4.2"]
    
    let screencasts = [swift41Screencast, swift42Screencast]
    let encoder = JSONEncoder()
    do {
      try encoder.encode(screencasts)
    } catch {
      print("\(error)")
    }
    

    3.6.2 条件遵守运行时查询

    Swift 4.2 实现条件遵守的动态查询。可以从下面的例子看出。

    // 1
    class Instrument {
      let brand: String
      
      init(brand: String = "") {
        self.brand = brand
      }
    }
    
    // 2
    protocol Tuneable {
      func tune()
    }
    
    // 3
    class Keyboard: Instrument, Tuneable {
      func tune() {
        print("\(brand) keyboard tuning.")
      }
    }
    
    // 4
    extension Array: Tuneable where Element: Tuneable {
      func tune() {
        forEach { $0.tune() }
      }
    }
    
    // 5
    let instrument = Instrument()
    let keyboard = Keyboard(brand: "Roland")
    let instruments = [instrument, keyboard]
    
    // 6
    if let keyboards = instruments as? Tuneable {
      keyboards.tune()
    } else {
      print("Can't tune instrument.")
    }
    

    注:上面在条件遵循的运行时检测中,会输出 "Can't tune instrument.",因为Instrument类型不遵守 Tuneable 协议,如果是两个 Keyboard 类型就可以。

    3.6.3 Hashable 在标准库中条件遵守增强

    在 Swift 4.2 中可选值、数组、字典和区间当他们的元素是 Hashable 的话,他们也是 Hashable

    struct Chord: Hashable {
      let name: String
      let description: String?
      let notes: [String]
      let signature: [String: [String]?]
      let frequency: CountableClosedRange<Int>
    }
    
    let cMajor = Chord(name: "C", description: "C major", notes: ["C", "E",  "G"], 
                       signature: ["sharp": nil,  "flat": nil], frequency: 432...446)
    let aMinor = Chord(name: "Am", description: "A minor", notes: ["A", "C", "E"], 
                       signature: ["sharp": nil, "flat": nil], frequency: 440...446)
    let chords: Set = [cMajor, aMinor]
    let versions = [cMajor: "major", aMinor: "minor"]
    

    3.7 Hashable 增强

    Swift 4.1 中一般会像下面这样实现自定义哈希函数:

    class Country: Hashable {
      let name: String
      let capital: String
      
      init(name: String, capital: String) {
        self.name = name
        self.capital = capital
      }
      
      static func ==(lhs: Country, rhs: Country) -> Bool {
        return lhs.name == rhs.name && lhs.capital == rhs.capital
      }
      
      var hashValue: Int {
        return name.hashValue ^ capital.hashValue &* 16777619
      }
    }
    
    let france = Country(name: "France", capital: "Paris")
    let germany = Country(name: "Germany", capital: "Berlin")
    let countries: Set = [france, germany]
    let countryGreetings = [france: "Bonjour", germany: "Guten Tag"]
    

    因为countriesHashable,所以可以添加到集合或者字典中。但是 hashValue 的实现很难理解并且也不高效。Swift 4.2 通过定义了一个通用的哈希函数来解决这个问题。

    class Country: Hashable {
      let name: String
      let capital: String
      
      init(name: String, capital: String) {
        self.name = name
        self.capital = capital
      }
      
      static func ==(lhs: Country, rhs: Country) -> Bool {
        return lhs.name == rhs.name && lhs.capital == rhs.capital
      }
    
      func hash(into hasher: inout Hasher) {
        hasher.combine(name)
        hasher.combine(capital)
      }
    }
    

    Country 中使用hash(into:) 来替代 hashValue。这个函数使用 combine() 将属性注入到 hasher中。

    注:现在实现上很容易,并且性能要比之前的版本高。

    3.8 集合中移除元素

    在 Swift 4.1 中,想要从集合中移除一个指定的元素,通常会使用filter(_:)的实现方式,在 Swift 4.2 添加了 removeAll(_:)

    // Swift 4.1
    var greetings = ["Hello", "Hi", "Goodbye", "Bye"]
    greetings = greetings.filter { $0.count <= 3 }
    // Swift 4.2
    greetings.removeAll { $0.count > 3 }
    

    3.9 更改布尔值

    在 Swift 4.1 中,我们通常会这样实现

    extension Bool {
      mutating func toggle() {
        self = !self
      }
    }
    
    var isOn = true
    isOn.toggle()
    

    Swift 4.2 给 Bool增加了 toggle()方法

    3.10 新的编译器指令

    Swift 4.2 定义了表述代码问题的编译器指令

    // 1
    #warning("There are shorter implementations out there.")
    
    let numbers = [1, 2, 3, 4, 5]
    var sum = 0
    for number in numbers {
      sum += number
    }
    print(sum)
    
    // 2
    #error("Please fill in your credentials.")
    
    let username = ""
    let password = ""
    switch (username.filter { $0 != " " }, password.filter { $0 != " " }) {
      case ("", ""):
        print("Invalid username and password.")
      case ("", _):
        print("Invalid username.")
      case (_, ""):
        print("Invalid password.")
      case (_, _):
        print("Logged in succesfully.")
    }
    

    #warning 用来输出警告信息,表示实现未完全完成
    #error 强制其他开发者填入 usernamepassword

    3.11 新的指针函数

    withUnsafeBytes(of:_:)withUnsafePointer(to:_:)在 Swift 4.1 中只能用于变量,所以必须拷贝一份。Swift 4.2 中该函数支持常量,不需要再保存值。

    // Swift 4.1
    let value = 10
    var copy = value
    withUnsafeBytes(of: &copy) { pointer in print(pointer.count) }
    withUnsafePointer(to: &copy) { pointer in print(pointer.hashValue) }
    // Swift 4.2
    withUnsafeBytes(of: value) { pointer in print(pointer.count) }
    withUnsafePointer(to: value) { pointer in print(pointer.hashValue) }
    

    3.12 Memory Layout 更新

    Swift 4.2 使用 keypath 查找存储属性的内存布局 [SE-0210],具体做法如下:

    // 1
    struct Point {
      var x, y: Double
    }
    
    // 2
    struct Circle {
      var center: Point
      var radius: Double
      
      var circumference: Double {
        return 2 * .pi * radius
      }
      
      var area: Double {
        return .pi * radius * radius
      }
    }
    
    // 3
    if let xOffset = MemoryLayout.offset(of: \Circle.center.x), 
       let yOffset = MemoryLayout.offset(of: \Circle.center.y), 
       let radiusOffset = MemoryLayout.offset(of: \Circle.radius) {
      print("\(xOffset) \(yOffset) \(radiusOffset)")
    } else {
      print("Nil offset values.")
    }
    
    // 4
    if let circumferenceOffset = MemoryLayout.offset(of: \Circle.circumference), 
       let areaOffset = MemoryLayout.offset(of: \Circle.area) {
      print("\(circumferenceOffset) \(areaOffset)")
    } else {
      print("Nil offset values.")
    

    注:可以通过 keypath 返回存储属性的内存偏移。计算属性返回 nil,因为没有存储关联。

    3.13 模块中的内联函数

    在 Swift 4.1 中,不允许在自己的模块中定义内联函数。依次选择 ViewNavigatorsShow Project Navigator, 右键单击Sources and 选择 New File。重命名文件为 FactorialKit.swift 并且替换为下面代码块中的代码。

    public class CustomFactorial {
      private let customDecrement: Bool
      
      public init(_ customDecrement: Bool = false) {
        self.customDecrement = customDecrement
      }
      
      private var randomDecrement: Int {
        return arc4random_uniform(2) == 0 ? 2 : 3
      }
      
      public func factorial(_ n: Int) -> Int {
        guard n > 1 else {
          return 1
        }
        let decrement = customDecrement ? randomDecrement : 1
        return n * factorial(n - decrement)
      }
    }
    

    在 Swift 4.2 中定义为内联的函数会更加高效,所以将 FactorialKit.swift 的代码替换如下。

    public class CustomFactorial {
      @usableFromInline let customDecrement: Bool
      
      public init(_ customDecrement: Bool = false) {
        self.customDecrement = customDecrement
      }
      
      @usableFromInline var randomDecrement: Int {
        return Bool.random() ? 2 : 3
      }
      
      @inlinable public func factorial(_ n: Int) -> Int {
        guard n > 1 else {
          return 1
        }
        let decrement = customDecrement ? randomDecrement : 1
        return n * factorial(n - decrement)
      }
    }
    

    四、其他更新

    下面是 Swift 4.2 中的一些其他改变

    4.1 Swift Package Manager 更新

    4.1.1 定义 Package 的 Swift 版本

    Swift 4.1 在 Package.swift 中定义了swiftLanguageVersions,所以可以在 packages 中定义主版本。

    let package = Package(name: "Package", swiftLanguageVersions: [4])
    

    Swift 4.2 中也能通过SwiftVersion定义小版本 [SE-0209]

    let package = Package(name: "Package", swiftLanguageVersions: [.v4_2])
    

    能够通过.version(_:)定义之后的版本

    let package = Package(name: "Package", swiftLanguageVersions: [.version("5")])
    

    4.1.2 Packages 定义本地版本

    在 Swift 4.1 中,可以使用仓库链接为 Package 定义依赖。如果有相互关联的 Package,就会产生额外的问题,所以 Swift 4.2 中引入了本地路径而提案[SE-0201]。

    4.1.3 给 Package 添加系统库 Target

    Swift 4.1 中系统模块包需要分仓库,这样包管理很难用 ,所以 Swift 4.2 使用系统库 Target 来实现 [SE-0208]

    4.2 移除隐式解包可选值

    在 Swift 4.1 中,你可以在嵌套类型中使用隐式解包可选值。

    let favoriteNumbers: [Int!] = [10, nil, 7, nil]
    let favoriteSongs: [String: [String]!] = ["Cosmin": ["Nothing Else Matters", "Stairway to Heaven"], "Oana": nil] 
    let credentials: (usermame: String!, password: String!) = ("Cosmin", nil)
    

    Swift 4.2 从数组、字典和元祖中移除了隐式解包可选值[ SE-0054]

    let favoriteNumbers: [Int?] = [10, nil, 7, nil]
    let favoriteSongs: [String: [String]?] = ["Cosmin": ["Nothing Else Matters", "Stairway to Heaven"], "Oana": nil] 
    let credentials: (usermame: String?, password: String?) = ("Cosmin", nil)
    

    感谢原作者 Cosmin Pupăză

    原文地址:https://www.raywenderlich.com/5357-what-s-new-in-swift-4-2

    附:大话Swift 4.1 epub 文件下载地址

    https://download.csdn.net/download/u010037928/10724897

    展开全文
  • \\\随着Swift 4.1进入beta阶段,Swift团队开始将注意力聚焦在新版本Swift 4.2的开发上。新版本除了bug修复和编译性能方面的改进,还会继续增强Application Binary Interface(ABI)稳定性。\\Swift 4.2的主要目标是...
    \

    看新闻很累?看技术新闻更累?试试下载InfoQ手机客户端,每天上下班路上听新闻,有趣还有料!

    \
    \\

    随着Swift 4.1进入beta阶段,Swift团队开始将注意力聚焦在新版本Swift 4.2的开发上。新版本除了bug修复和编译性能方面的改进,还会继续增强Application Binary Interface(ABI)稳定性。

    \\

    Swift 4.2的主要目标是为ABI稳定性做准备,ABI将会是Swift 5的主要目标。据苹果公司语言和运行时经理Ted Kremenek透露,Swift 4.2将会对ABI的底层做出一些与性能有关的改动,目的是在Swift 5中正式发布最终版的ABI之前,能够从开发者那里获取反馈。

    \\

    与Swift 4.2相关的代码都提交到swift-4.2-branch,每两周从master分支合并一次。从4月20号开始,在从master分支进行最后一次合并之后,swift-4.2-branch只接受关键的bug修复代码。

    \\

    ABI稳定性让不同版本Swift编译出来的应用程序和类库可以兼容,对于框架开发者来说,这是最基础的一项特性。如果缺乏ABI稳定性,那么就需要为不同版本的编译器提供不同版本的框架。ABI仪表盘上列出了ABI最终版需要包含的变更清单,将于2018年下半年发布,不过目前并不清楚哪些变更将被包含在Swift 4.2中,哪些将被包含在Swift 5中。

    \\

    为了遵守Swift 4的诺言,Swift 4.2会继续保证兼容4.x的代码,也就是说,能用Swift 4.x编译器编译的代码也可以使用Swift 4.2的编译器进行编译。不过,这并不包含因bug修复导致的破坏性变更,也就是那些因编译器的bug而能够通过编译的错误代码。在兼容模式下,仍然可以使用Swift 4.2来编译Swift 3的代码。

    \\

    Swift 4发布于2017年9月,目标是改进语言和编译器性能和稳定性,同时保持代码的兼容性。ABI稳定性原本是Swift 4的目标,后来被延期到了Swift 5中。

    \\

    查看英文原文Swift 4.2 Enters Final Development Stage, Paving the Way for Swift 5

    展开全文
  • Swift 4.2Swift 4的第二次小更新,随之带来了很多很棒的改进-这使得今年将成为Swift的重要一年,并且更加确认这个社区驱动的Swift演变进程正在让一个伟大的语言变得更好。这次我们获得了一些特性比如enum case ...


    Swift 4.2是Swift 4的第二次小更新,随之带来了很多很棒的改进-这使得今年将成为Swift的重要一年,并且更加确认这个社区驱动的Swift演变进程正在让一个伟大的语言变得更好。

    这次我们获得了一些特性比如enum case 数组,warning与error编译指令,动态成员查找等等,这些都是Swift 4.1新特性(详见我的文章what's new in Swift 4.1)之外新增加的。Swift 4.2现在距离主代码分支的最终合并仅相差几天,届时只有一些重要修正会加入。如果将来有任何改变,文中这些例子也会更新。

    直到一个新版的Xcode与Swift4.2一起发布,你就可以下载最新版的Swift主干开发快照并在你当前Xcode版本上激活它。

    • 试着自己做:我创建了一个 Xcode playground展示Swift 4.2新内容,你可以编辑里面的实例。

    enum案例的衍生集合

    SE-0194介绍了一个新的CaseIterable协议,它会对一个enum中的所有cases自动生成一个数组(array)属性。

    在Swift 4.2之前,它需要 hacks, hand-coding, 或者源代码生成才能实现,但是现在你需要的仅仅是让你的enum符合CaseIterable协议。在编译时,Swift会自动生成一个allCases属性,这个allCases是一个按照你定义的顺序排列,包含所有enum’s cases的数组。

    例如,如下创建一个pasta形的enum,并要求Swift去自动为它创建一个allCases数组

    enum Pasta: CaseIterable {

    casecannelloni, fusilli, linguine, tagliatelle

    }

    你可以更进一步,像使用一个普通数组一样用这个属性- 把[Pasta]放在代码前,我们就可以这样输入

    forshape inPasta.allCases {

    print("I like eating \(shape).")

    }

    这个allCases的自动合成仅替换并不使用关联数值的enums。加入下面这些并不会自动生效,但是如果需要你可以自己添加。

    enum Car: CaseIterable {

    staticvarallCases: [Car] {

    return[.ford, .toyota, .jaguar, .bmw, .porsche(convertible: false), .porsche(convertible: true)]

    }

    caseford, toyota, jaguar, bmw

    caseporsche(convertible: Bool)

    }

    这时如果你的任何一个enum cases被标记为unavailable,Swift就不能合成allCases属性。所以如果你需要allCases,你要像下面这样自己添加它:

    enum Direction: CaseIterable {

    staticvarallCases: [Direction] {

    return[.north, .south, .east, .west]

    }

    casenorth, south, east, west

    @available(*, unavailable)

    caseall

    }

    注意:要想allCases 数组被合成,你需要添加CaseIterable而不是一个extension到你enum的原始声明中。这意味着你不能用extension反向地让已存在的enums遵守一个协议。

    Warning与error诊断指令

    SE-0196介绍新的编译指令来帮助我们在代码中标记 issues. 这对使用过Objective-C的开发者应该很熟悉了,随着Swift 4.2的发布,我们也能在Swift中使用它了

    这两个指令是#warning和#error,前者会强制Xcode在生成你的代码时发出一个警告,后者会发出一个编译错误这样你的代码就完全不能生成。下面说明了它们的用处

    • #warning主要用于提醒你或者别人一些工作还没有完成,Xcode模板常使用#warning标记一些你需要替换成自己代码的方法存根(method stubs)。

    • #error主要用于如果你发送一个库,需要其他开发者提供一些数据。比如,一个网络 API的认证密码,你需要用户输入它们自己的密码,就使用#error在继续之前强制他们更改这行代码。

    它们的使用方式都一样,#warning("Some message") 和 #error("Some message"),例如

    func encrypt(_ string: String, withpassword: String) -> String{

    #warning("This is terrible method of encryption")

    returnpassword + String(string.reversed()) + password

    }

    struct Configuration {

    varapiKey: String{

    #error("Please enter your API key below then delete this line.")

    return"Enter your key here"

    }

    }

    #warning和#error可以和已存的#if编译指令共同使用,并且只有在条件为true时才会激活。例如:

    #ifos(macOS)

    #error("MyLibrary is not supported on macOS.")

    #endif

    动态成员查找

    SE-0195介绍了一个方法,让Swift更接近脚本语言比如Python,但是用一种类型安全的方法-你不会失去任何Swift的安全性,但是你确实增强了写类似PHP和Python代码的能力。

    这个特性的核心在于一个新属性,称作@dynamicMemberLookup,它命令Swift使用一种下标方法去进行属性访问。这种下标方法,需要subscript(dynamicMember:):你可以通过所请求属性的字符串名得到,并且可以返回你想要的任何值。

    让我们看一个小例子这样你就可以知道基本了。我们可以创建一个Person结构,并且从一个字典读取它的值,像这样

    @dynamicMemberLookup

    struct Person {

    subscript(dynamicMember member: String) -> String{

    let properties = ["name": "Taylor Swift", "city": "Nashville"]

    returnproperties[member, default: ""]

    }

    }

    @dynamicMemberLookup 属性需要一个类型去执行subscript(dynamicMember:)方法,从而处理一件实际的动态成员查找工作。你可以看到,我写了一个代码,按字符串接收成员名字,并返回一个字符串。从内部看它只是在一个字典中查找这个成员名字并返回它的值。

    这种结构允许我们这样写代码:

    let person = Person()

    print(person.name)

    print(person.city)

    print(person.favoriteIceCream)

    它会干净地编译运行,即使name, city, 和favoriteIceCream并不作为Person类型中的属性存在。相反,它们都在运行时被查找。在前两次呼叫print()时,代码会打出Taylor Swift” 和 “Nashville”,而最后一次会是一个空白字符串,因为我们的字典并不存储任何favoriteIceCream

    我的subscript(dynamicMember:) 方法必须返回一串字符,这体现了Swift的类型安全性。即使你在处理动态数据,Swift依旧保证你会得到你想要的。如果你想要多种不同的类型,就执行不同的subscript(dynamicMember:)方法,像这样

    @dynamicMemberLookup

    struct Employee {

    subscript(dynamicMember member: String) -> String{

    let properties = ["name": "Taylor Swift", "city": "Nashville"]

    returnproperties[member, default: ""]

    }

    subscript(dynamicMember member: String) -> Int {

    let properties = ["age": 26, "height": 178]

    returnproperties[member, default: 0]

    }

    }

    现在任何属性都可以通过不止一种方式被访问,Swift需要你知道应该运行哪一种。它可以是内部的,比如如果你向一个只接收字符串的函数传递返回值,或者它可以是外部的,像这样

    let employee = Employee()

    let age: Int = employee.age

    无论哪种方式,Swift必须明确知道哪种下标要被呼叫

    你甚至可以强行要求subscript返回一个闭包(Closure):

    @dynamicMemberLookup

    struct User {

    subscript(dynamicMember member: String) -> (_ input: String) -> Void {

    return{

    print("Hello! I live at the address \($0).")

    }

    }

    }

    let user = User()

    user.printAddress("555 Taylor Swift Avenue")

    当它运行时,user.printAddress返回一个闭包,即输出一串字符,之后("555 Taylor Swift Avenue")部分立即通过这串字符来呼叫它。

    如果你对包含一些普通属性和方法的类型使用动态成员下标,这些属性和方法会始终代替动态成员被使用。例如,我们可以定义一个附有动态成员下标的Singer结构,其中内置有name属性

    struct Singer {

    publicvarname = "Justin Bieber"

    subscript(dynamicMember member: String) -> String{

    return"Taylor Swift"

    }

    }

    let singer = Singer()

    print(singer.name)

    这个代码会打出“Justin Bieber”,因为name属性会代替动态成员下标被使用

    @dynamicMemberLookup完全参与到Swift的类型系统中,这意味着你可以用在protocols, structs, enums,和 classes中,即使classes被标记为@objc

    实际中,这意味着两件事情。首先,你可以使用@dynamicMemberLookup建立一个类,并且任何从它继承的类都会自动为@dynamicMemberLookup属性. 所以,下例会打出“I’m a sandwich”,因为HotDog继承于Sandwich

    @dynamicMemberLookup

    classSandwich {

    subscript(dynamicMember member: String) -> String{

    return"I'm a sandwich!"

    }

    }

    classHotDog: Sandwich { }

    let chiliDog = HotDog()

    print(chiliDog.description)

    注意:如果你不认为热狗是三明治,那就来我的推特打我呀

    第二,你可以通过在协议中定义,来反向地让其他类型使用@dynamicMemberLookup,通过扩展协议 添加一个默认执行的subscript(dynamicMember:),之后让其他类型按你想要的方式符合你的协议。

    例如,下例创建了一个新的Subscripting协议,提供一个默认的subscript(dynamicMember:),它会返回一条信息,之后扩展Swift的String去使用这个协议。

    @dynamicMemberLookup

    protocol Subscripting { }

    extension Subscripting {

    subscript(dynamicMember member: String) -> String{

    return"This is coming from the subscript"

    }

    }

    extension String: Subscripting { }

    let str = "Hello, Swift"

    print(str.username)

    在他的Swift演变提案中, Chris Lattner也给了一个JSON enum的例子,即使用动态成员查找通过JSON为引导(navigating)建立更自然的语法

    @dynamicMemberLookup

    enum JSON {

    caseintValue(Int)

    casestringValue(String)

    casearrayValue(Array)

    casedictionaryValue(Dictionary)

    varstringValue: String? {

    ifcase.stringValue(let str) = self {

    returnstr

    }

    returnnil

    }

    subscript(index: Int) -> JSON? {

    ifcase.arrayValue(let arr) = self {

    returnindex < arr.count ? arr[index] : nil

    }

    returnnil

    }

    subscript(key: String) -> JSON? {

    ifcase.dictionaryValue(let dict) = self {

    returndict[key]

    }

    returnnil

    }

    subscript(dynamicMember member: String) -> JSON? {

    ifcase.dictionaryValue(let dict) = self {

    returndict[member]

    }

    returnnil

    }

    }

    没有动态成员查找你将需要为JSON enum 引导一个实例 ,像这样

    let json = JSON.stringValue("Example")

    json[0]?["name"]?["first"]?.stringValue

    但是有了动态成员查找你可以用下面这个

    json[0]?.name?.first?.stringValue

    我认为这个例子特别重要,因为它指出了@dynamicMemberLookup的要点,它能把定制下标转化为简单的点语法

    注意:使用动态成员查找意味着如果不具备全部的有效性,代码的完成会损失很多,因为不存在东西去完成。尽管这不算是什么惊喜,这也是Python IDEs有时不得不处理的问题。Chris Lattner (SE-0195的作者)在他的提案中讨论了未来关于代码完成的可能性,它值得一读

    增强的条件一致性

    条件一致性在Swift 4.1中引入,允许当特定条件被满足时,类型就去符合一个协议。

    例如,如果我们有Purchaseable协议

    protocol Purchaseable {

    func buy()

    }

    和一个符合这个协议的简单类型

    struct Book: Purchaseable {

    func buy() {

    print("You bought a book")

    }

    }

    之后如果数组中所有元素符合Purchasable,我们就可以让数组符合Purchaseable,

    extension Array: Purchaseable where Element: Purchaseable {

    func buy() {

    foritem inself {

    item.buy()

    }

    }

    }

    在编译时它运行的很好,但是有一个问题,如果你要在运行时查询一个条件一致性,你的代码会崩溃,因为这在Swift 4.1中不支持。

    现在,在Swift 4.2中已经被修复,所以如果你收到一种类型的数据,想要检查它是否可以被转化为一个条件一致性协议,它可以做到了。

    例如

    let items: Any = [Book(), Book(), Book()]

    iflet books = items as? Purchaseable {

    books.buy()

    }

    另外,对Hashable一致性自动合并的支持在Swift 4.2被大幅提高,来自Swift 标准库的几个内置类型,包括optionals, arrays, dictionaries, 和 ranges-现在当他们的元素符合Hashable时会自动符合Hashable 协议

    例如:

    struct User: Hashable {

    varname: String

    varpets: [String]

    }

    Swift 4.2 可以为这个结构自动合并 Hashable一致性, 但Swift 4.1不能.

    本地集合元素移除

    SE-0197介绍一个新的 removeAll(where:) 方法,它具有高性能,本地为集合过滤。给它一个闭合环境运行,它会除去所有符合条件的目标。

    例如,如果你有一个名称的collection,并且想移除叫“Terry”的人,你可以用这个

    varpythons = ["John", "Michael", "Graham", "Terry", "Eric", "Terry"]

    pythons.removeAll { $0.hasPrefix("Terry") }

    print(pythons)

    现在,你也许会想到你可以通过filter()来实现,像这样

    pythons = pythons.filter { !$0.hasPrefix("Terry") }

    然而,这样并不能有效利用存储,它指定你不需要的而不是你想要的,而且更高级的本地方法会带来一系列复杂性,这些是新手很讨厌的。

    布尔值切换

    SE-0199为布尔值带来了一个新的toggle()方法,即在true和false之间翻转。这个引发了Swift社区的一片讨论,部分人认为它太细枝末节,也有部分是因为Swift论坛的讨论时不时变得失控。

    执行这个提案的完整代码仅仅几行

    extension Bool {

    mutating func toggle() {

    self = !self

    }

    }

    然而,它最终有助于让Swift代码变得更自然

    varloggedIn = false

    loggedIn.toggle()

    就像这个提案中提到,它在更复杂的数据结构中特别有用:

    myVar.prop1.prop2.enabled.toggle()避免了在手动操作时潜在的输入错误。=

    这个提案让Swift更简单安全的写入,并且完全是附加的,所以我认为大部分人会很快去使用它。

    展望Swift 5.0

    苹果形容Swift 4.2为”为了实现Swift 5中ABI稳定性的中继点”,但是我希望你能明白这是一个很保守的声明-我们正在得到一些很好的新特性,既有对过去特性的改进,也有ABI的改变。

    更好的是,在最终发布之前我们也许还会看到新的特性被加入-我们可能同时看到SE-0192, SE-0193, SE-0202, 和SE-0206的到来。

    然而,我们归根结底依旧期待Swift 5.0能提供大家盼望已久的ABI稳定性。苹果谨慎小心步步为营的方法似乎会走的更好,而且它让人怀有希望,觉得Swift 5.0将会更值得等待。

    展开全文
  • swift4.2标准库更改

    2018-09-25 16:41:20
    swift4.2发布了 1、RangeReplaceableCollection 集合添加根据条件删除方法(官方原文) protocol RangeReplaceableCollection { /// Removes every element satisfying the given predicate from the collection. ...

    swift4.2发布了

    1、RangeReplaceableCollection 集合添加根据条件删除方法(官方原文)

    protocol RangeReplaceableCollection {
      /// Removes every element satisfying the given predicate from the collection.
      mutating func removeAll(where: (Iterator.Element) throws -> Bool) rethrows
    }
    
    extension RangeReplaceableCollection {
      mutating func removeAll(where: (Iterator.Element) throws -> Bool) rethrows {
        // default implementation similar to self = self.filter
      }
    }

    比如:

    struct Person{
        let name:String?
        let age:Int
    }
    
    var arr = [Person(name: nil, age: 1),
                       Person(name: "b", age: 2),
                       Person(name: "c", age: 3),
                       Person(name: "d", age: 4)]
    arr.removeAll {$0.age<2}
    
    //[Person(name: Optional("b"), age: 2), Person(name: Optional("c"), age: 3), Person(name: Optional("d"), age: 4)]

    跟以前的filter方法比较是在集合本身进行修改,而filter的方法闭是返回闭包为真的集合。

     

    2、Bool变量添加切换方法(官方原文)

    extension Bool {
      /// Equivalent to `someBool = !someBool`
      ///
      /// Useful when operating on long chains:
      ///
      ///    myVar.prop1.prop2.enabled.toggle()
      mutating func toggle() {
        self = !self
      }
    }

    以后可以这样切换了 model.model2?.model3.enabled.toggle()

    3、随机统一(官方原文)

    以前随机数要用到arc4random()函数

    现在 

    var myRandom = SystemRandomNumberGenerator()
    let num = Int.random(in: 0..<10, using: &myRandom)
    

    而且可以在一个集合中随机生成一个集合内的元素

    let arr = [1,4,6,9,11,12]
    arr.randomElement()

    也可以在集合中做洗牌操作

    var myRandom = SystemRandomNumberGenerator()
    var arr = [1,4,6,9,11,12]
            
    arr.shuffle(using: &myRandom)

     

    4、添加last(where:)和lastIndex(where:)方法(官方原文)

    在集合中添加从后面搜索索引和查找元素方法

    let arr = ["aa","bbbb","ddddd","ccccc","kas"]
    //从后面开始查找元素
    arr.last{$0.count>4}//返回ccccc
    //从后面开始查找索引
    arr.lastIndex{$0.count>4}//返回3

    5、Hashable增强(官方原文)

    标准库新增Hasher结构体,Hasher在系统每次执行,会生成不同的哈希种子,这个种子是随机生成的,Hasher为Hashable的生成提供捕获哈希状态。

    struct Person:Hashable{
        let name:String
        let age:Int
    }
    

    系统会有默认实现

    var hashValue: Int{
         var hash = Hasher()//系统在没重新启动的时候 这个方法生成的值相同,重启后这个值会变
         self.hash(into: &hash)
         return hash.finalize()
     }
     
     func hash(into hasher: inout Hasher){
         hasher.combine(name)
         hasher.combine(age)
     }

    6、Sequence新增allSatisfy算法(官方原文)

    let arr = [1,2,3,5,6,7,8,9]
    arr.allSatisfy{$0>0}//true
    arr.allSatisfy{$0>1}//false

     

    展开全文
  • 经过大约一个月的时间的适配,项目正式使用XCode10(以下简称为10 or XC10)大部分库都升级为Swift4.2(以下简称为 4.2 or S4.2),下面是适配过程中遇到的一些坑。 1. Swift4、Swift4.2混编 如果你对项目是小的独立...

    以下是2018年10月23日更新

    经过大约一个月的时间的适配,项目正式使用XCode10(以下简称为10 or XC10)大部分库都升级为Swift4.2(以下简称为 4.2 or S4.2),下面是适配过程中遇到的一些坑。

    1. Swift4、Swift4.2混编

    如果你对项目是小的独立项目,完全可以全部升级为4.2,你可以略过第一条;如果你依赖了一些第三方的库,且没有升级4.2,你可以继续看这一条。目前测试的结果来看,Swift4 和 S4.2的混编没有什么大的问题,如果你是通过cocoapod引入的可以在Podfile中加入如下代码:

    swift_41_pod_targets = ['your_target_name']
    post_install do |installer|
      installer.pods_project.targets.each do |target|
        if swift_41_pod_targets.include?(target.name)
          target.build_configurations.each do |config|
            config.build_settings['SWIFT_VERSION'] = '4.1'
          end
        end
      end
    end
    复制代码

    2. NSDataAsset

    升级XC10和S.2之前,项目里面有些对 'NSDataAsset' 的错误使用: 用‘NSDataAsset’读ImageAsset中的图片,这个是不正确的,但是却可以工作,这次升级修复了这个BUG。

    正确的做法使用'DataAsset',然后才可以用‘NSDataAsset’读取数据,我由于不够认真且经验不足还以为是个BUG,给Apple提了个BUG。。。[捂脸]

    3. 第三方库的重命名 typealias

    为了方便的适配S4.2对UIKit中的重命名,有些第三方使用typealias对一些类型进行了重命名,以 RxSwift 为例子,RxSwift中就有如下代码:

    #if swift(>=4.2)
        public typealias UIControlEvents = UIControl.Event  private
    #endif
    复制代码

    这会导致一些重命名的类型即使不改也不会报错,但是一旦去掉了对某个库的依赖就会引入新的问题。

    4.Delegate 的 Access Modifier

    在升级S4.2过程中,XC偶尔会提示需要给某些Delegate方法添加 private修饰符,不要为了消除这个⚠️添加private,可能会导致Delegate永远不被调到;另外,如果是一个public或者openclass,协议方法记得也要加上public,否则会出一样的问题,具体原因我还在测试,但是现象是这样的,有新的见解欢迎评论区讨论。

    5. 机型适配问题,iPhone XS Max字体变大

    有些同事遇到XC9构建的安装包在iPhone XS Max上会有字体变大的情况,这个貌似是普遍现象,微信也有,使用XC10构建安装包可以解决这个问题,但是会遇到问题6

    ###6. iOS9.3以下系统Crash率飙升 使用XC10构建安装包可以解决问题5,但是iOS9.3以下的系统Crash到让你怀疑人生

    以下是2018年9月18日内容

    AVAudioSession.sharedInstance().setCategory()

    disappeared

    Swift 4.2 中 iOS10以下不能用 AVAudioSession.sharedInstance() setCategory

    可选方案:
    • 使用OC实现该部分,然后使用Swift调用
    • 放弃 iOS9用户体验

    参考地址

    do {
        if #available(iOS 11.0, *) {
            try audioSession.setCategory(.playback, mode: .default, policy: .longForm, options: [])
        } else if #available(iOS 10.0, *) {
            try audioSession.setCategory(.playback, mode: .default, options: [])
        } else {
            // Compiler error: 'setCategory' is unavailable in Swift
            try audioSession.setCategory(AVAudioSession.Category.playback)
        }
    } catch let error {
        print("Unable to configure audio sesson category: \(error)")
    }
    复制代码

    NSUnderlineStyle(.patternSolid、.none)

    disappeared

    可选方案:
    • .none

      mutableAttributedString.addAttribute(NSAttributedString.Key.underlineStyle, value: NSUnderlineStyle.none.rawValue, range: range) ^~~~~ 'none' is unavailable: use [] to construct an empty option set

    Wrong: mutableAttributedString.addAttribute(NSAttributedString.Key.underlineStyle, value: [], range: range) Right: mutableAttributedString.addAttribute(NSAttributedString.Key.underlineStyle, value: 0, range: range)

    • 使用 CTUnderlineStyleModifiers

      // 没有测试 NSUnderlineStyle.init(rawValue: Int(CTUnderlineStyleModifiers.patternSolid.rawValue))

    • 使用其他默认值

    下面是Rename操作

    UIKit

    #Swift4/UIKit

    UITableViewCell

    Swift 4 Swift 4.2
    UITableViewCellStyle UITableViewCell.CellStyle

    UIEvent

    Swift 4 Swift 4.2
    UIEventSubtype UIEvent.EventSubtype

    UITableView

    Swift 4 Swift 4.2
    UITableViewScrollPosition UITableView.ScrollPosition
    UITableViewAutomaticDimension UITableView.automaticDimension
    UITableViewCellEditingStyle UITableViewCell.EditingStyle
    UITableViewRowAnimation UITableView.RowAnimation
    UITableViewStyle UITableView.Style
    UITableViewCellAccessoryType UITableViewCell.AccessoryType

    UIControl

    Swift 4 Swift 4.2
    UIControlEvents UIControl.Event

    UIWindow

    Swift 4 Swift 4.2
    UIWindowLevelAlert UIWindow.Level.alert
    UIKeyboardFrameEndUserInfoKey UIResponder.keyboardFrameEndUserInfoKey
    UIKeyboardFrameBeginUserInfoKey UIResponder.keyboardFrameBeginUserInfoKey
    UIKeyboardAnimationDurationUserInfoKey UIResponder.keyboardAnimationDurationUserInfoKey
    UIKeyboardAnimationCurveUserInfoKey UIResponder.keyboardAnimationCurveUserInfoKey
    UIKeyboardIsLocalUserInfoKey UIResponder.keyboardIsLocalUserInfoKey
    UIWindowDidBecomeVisible UIWindow.didBecomeVisibleNotification
    UIWindowDidBecomeHidden UIWindow.didBecomeHiddenNotification
    UIWindowDidBecomeKey UIWindow.didBecomeKeyNotification
    UIWindowDidResignKey UIWindow.didResignKeyNotification
    UIKeyboardWillShow UIResponder.keyboardWillShowNotification
    UIKeyboardDidShow UIResponder.keyboardDidShowNotification
    UIKeyboardWillHide UIResponder.keyboardWillHideNotification
    UIKeyboardDidHide UIResponder.keyboardDidHideNotification

    UIViewController

    Swift 4 Swift 4.2
    open func addChildViewController(_ childController: UIViewController) open func addChild(_ childController: UIViewController)
    open func willMove(toParentViewController parent: UIViewController?) open func willMove(toParent parent: UIViewController?)
    open func didMove(toParentViewController parent: UIViewController?) open func didMove(toParent parent: UIViewController?)
    open func removeFromParentViewController() open func removeFromParent()

    UIActivity

    Swift 4 Swift 4.2
    UIActivityType UIActivity.ActivityType

    UIActivityIndicatorView

    Swift 4 Swift 4.2
    activityIndicator.activityIndicatorViewStyle activityIndicator.style

    UIAlertController

    Swift 4 Swift 4.2
    UIAlertActionStyle UIAlertAction.Style
    UIAlertControllerStyle UIAlertController.Style

    UIPageViewController

    Swift 4 Swift 4.2
    UIPageViewControllerNavigationDirection UIPageViewController.NavigationDirection
    UIPageViewControllerSpineLocation UIPageViewController.SpineLocation
    UIPageViewControllerNavigationOrientation UIPageViewController.NavigationOrientation
    UIPageViewControllerTransitionStyle UIPageViewController.TransitionStyle
    UIPageViewControllerOptionsKey UIPageViewController.OptionsKey

    UINavigationController

    Swift 4 Swift 4.2
    UINavigationControllerOperation UINavigationController.Operation

    UIGestureRecognizer

    Swift 4 Swift 4.2
    UIGestureRecognizerStatePossible UIGestureRecognizer.State.possible
    UIGestureRecognizerStateBegan UIGestureRecognizer.State.began
    UIGestureRecognizerStateChanged UIGestureRecognizer.State.changed
    UIGestureRecognizerStateEnded UIGestureRecognizer.State.ended
    UIGestureRecognizerStateCancelled UIGestureRecognizer.State.cancelled
    UIGestureRecognizerStateFailed UIGestureRecognizer.State.failed
    UIGestureRecognizerStateRecognized UIGestureRecognizer.State.recognized

    NSLayoutFormat

    Swift 4 Swift 4.2
    NSLayoutFormatOptions NSLayoutConstraint.FormatOptions

    UIEdgeInsets

    Swift 4 Swift 4.2
    public func UIEdgeInsetsMake(_ top: CGFloat, _ left: CGFloat, _ bottom: CGFloat, _ right: CGFloat) -> UIEdgeInsets UIEdgeInsets(top: CGFloat, left: CGFloat, bottom: CGFloat, right: CGFloat)
    public func UIEdgeInsetsInsetRect(_ rect: CGRect, _ insets: UIEdgeInsets) -> CGRect public func inset(by insets: UIEdgeInsets) -> CGRect

    UIFontDescriptor

    Swift 4 Swift 4.2
    UIFontDescriptorSymbolicTraits UIFontDescriptor.SymbolicTraits

    UIImage

    Swift 4 Swift 4.2
    UIKIT_EXTERN NSData * __nullable UIImagePNGRepresentation(UIImage * __nonnull image); public func pngData() -> Data?
    NSData * __nullable UIImageJPEGRepresentation(UIImage * __nonnull image, CGFloat compressionQuality); public func jpegData(compressionQuality: CGFloat) -> Data?

    UIApplication

    Swift 4 Swift 4.2
    UIApplicationDidEnterBackground UIApplication.didEnterBackgroundNotification
    UIApplicationWillEnterForeground UIApplication.willEnterForegroundNotification
    UIApplicationDidFinishLaunching UIApplication.didFinishLaunchingNotification
    UIApplicationDidBecomeActive UIApplication.didBecomeActiveNotification
    UIApplicationWillResignActive UIApplication.willResignActiveNotification
    UIApplicationDidReceiveMemoryWarning UIApplication.didReceiveMemoryWarningNotification
    UIApplicationWillTerminate UIApplication.willTerminateNotification
    UIApplicationSignificantTimeChange UIApplication.significantTimeChangeNotification
    UIApplicationWillChangeStatusBarOrientation UIApplication.willChangeStatusBarOrientationNotification
    UIApplicationDidChangeStatusBarOrientation UIApplication.didChangeStatusBarOrientationNotification
    UIApplicationDidChangeStatusBarFrame UIApplication.didChangeStatusBarFrameNotification
    UIApplicationBackgroundRefreshStatusDidChange UIApplication.backgroundRefreshStatusDidChangeNotification
    UIApplicationProtectedDataWillBecomeUnavailable UIApplication.protectedDataWillBecomeUnavailableNotification
    UIApplicationProtectedDataDidBecomeAvailable UIApplication.protectedDataDidBecomeAvailableNotification
    UIApplicationUserDidTakeScreenshot UIApplication.userDidTakeScreenshotNotification
    UIApplicationOpenSettingsURLString UIApplication.openSettingsURLString
    UIApplicationLaunchOptionsKey UIApplication.LaunchOptionsKey
    UIInterfaceOrientationIsLandscape() UIApplication.shared.statusBarOrientation.isLandscape

    UIView

    Swift 4 Swift 4.2
    func bringSubview(toFront view: UIView) func bringSubviewToFront(_ view: UIView)
    UIViewAnimationOptions UIView.AnimationOptions()

    Foundation

    NSAttributedString

    Swift 4 Swift 4.2
    NSAttributedStringKey NSAttributedString.Key

    QuartzCore

    CAShapeLayer

    Swift 4 Swift 4.2
    kCALineCapRound CAShapeLayerLineCap.round
    kCALineCapButt CAShapeLayerLineCap.butt
    kCALineCapSquare CAShapeLayerLineCap.square
    kCALineJoinMiter CAShapeLayerLineJoin.miter
    kCALineJoinRound CAShapeLayerLineJoin.round
    kCALineJoinBevel CAShapeLayerLineJoin.bevel
    kCAFillRuleNonZero CAShapeLayerFillRule.nonZero
    kCAFillRuleEvenOdd CAShapeLayerFillRule.evenOdd

    参考资料

    Swift-Migration-4.2

    转载于:https://juejin.im/post/5ba0dfb9e51d450e4a1babcb

    展开全文
  • 可以说是最用心的关于swift4.2的中文翻译版本了;但下载的PDF都是分散的一个个的文件,现在把它整理到单一的文件中,方便了学习。请开心不用切换干扰下学习吧~~~
  • Swift 4.2正式发布

    2019-04-09 09:40:27
    Swift 4发布了一年之后,Swift 4.2版本也正式推出。这一版本带来了语言和标准库方面的改进,包括更好的泛型、Hashable协议以及随机数生成。另外,Swift语言维护者Ted Kremenek写道,Swift 4能提供更快的编译速度,...
  • Swift 提供了三种基本数据类型,包括数组、集合、字典,都可用于存储值集合。数组是值的有序集合。集合是无序值的唯一值集合。字典是关键值关联的无序集合。   Swift 中的数组、集合、字典对它们可以存储的值和...
  • 本文记录了将工作项目由Swift4版本升级到Swift4.2中修改的内容,需要修改876处错误: ‘UIImageOrientation’ has been renamed to ‘UIImage.Orientation’ ‘UIApplicationWillResignActive’ has been ...
  • Get started with push notifications on iOS! Currently updated to: Platform: iOS12; Language: Swift4.2; Editor: Xcode10
  • swift里字符串进行了一些扩展,基本就是重写了oc sub方法 1.从头切,切到哪里. str.bdSubString(to: 6) 2.从哪里切,切到头 str.bdSubString(from: 2) 3从哪里切到哪里 str.bdSubString(from: 0, to: 6) 4 ...
  • Core Data By Tutorials Fifth Edition IOS 12 and Swift 4.2 edittion Ray Wenderlich Download PDF
  • Swift 4.2 新特性更新

    2019-02-27 00:20:05
    Swift 4.2Swift 4.0发布以来的第二次小更新, 继上次Xcode 9.3和Swift 4.1发布以来也有俩月有余 上个版本Swift 4.1 的新特性中介绍了条件一致性和哈希索引等相关更新 随着Xcode Bate 10的发布, Swift 4.2也发布了...
  • 参考项目实际、官方文档、raywenderlich(传送门)等大神总结的swift语言的编码规范,适应目前swift 4.2,笔者会不定期更新,欢迎指正补充 约定,请尽量确保代码编译不残留warning,这有可以规避很多问题 目录命名...
  • swift4.2 之AVFoundation 调用摄像头 override func viewDidLoad() { super.viewDidLoad() setupScanSession() startScan() } //MARK: 方法 func setupScanSession(){ do{ //设置捕捉设备 ...
1 2 3 4 5 ... 20
收藏数 3,437
精华内容 1,374
热门标签
关键字:

swift4.2