前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Swift 3到5.1新特性整理

Swift 3到5.1新特性整理

作者头像
小刀c
发布2022-08-16 15:06:41
4.7K0
发布2022-08-16 15:06:41
举报
文章被收录于专栏:cc log

toc

Swift 5.1

Swift 5.1的更新比较迟,单独成篇Swift 5.1的变化

Swift 5.0

Swift 5.0 最重要的自然是ABI Stability, 对此可以看这篇 Swift ABI 稳定对我们到底意味着什么

当然还有其他的更新。

Result类型

SE-0235提议的实现。用来在复杂对象中的错误处理。

Result类型有两个带泛型的枚举成员successfailure,而且failure的泛型必须遵循Swift的Error类型。

常规的使用

代码语言:javascript
复制
enum NetworkError: Error {
    case badURL
}

import Foundation

func fetchUnreadCount1(from urlString: String, completionHandler: @escaping (Result<Int, NetworkError>) -> Void)  {
    guard let url = URL(string: urlString) else {
        completionHandler(.failure(.badURL))
        return
    }

    // complicated networking code here
    print("Fetching \(url.absoluteString)...")
    completionHandler(.success(5))
}

fetchUnreadCount1(from: "https://www.hackingwithswift.com") { result in
    switch result {
    case .success(let count):
        print("\(count) unread messages.")
    case .failure(let error):
        print(error.localizedDescription)
    }
}

首先,Result有个get()方法,要么返回成功值,要么抛出错误。那么可以这么使用。

代码语言:javascript
复制
fetchUnreadCount1(from: "https://www.hackingwithswift.com") { result in
    if let count = try? result.get() {
        print("\(count) unread messages.")
    }
}

再次,Result可以接受一个闭包来初始化,如果闭包成功返回,就会把它放到success的一边,如果抛出错误,就放到failure的一边。

代码语言:javascript
复制
let result = Result { try String(contentsOfFile: someFile) }

最后,你可以使用你自己的错误枚举,但是Swift官方建议,你说用Swift.Error来作为Error的参数。

“it’s expected that most uses of Result will use Swift.Error as the Error type argument.”

Raw string

SE-0200 引入了,使用#来包裹的Raw字符串,里面的字符不会做处理,特别是一些转义字符。

差值需要这样做

代码语言:javascript
复制
let answer = 42
let dontpanic = #"The answer to life, the universe, and everything is \#(answer)."#

这个对于正则的特别好用

代码语言:javascript
复制
let regex1 = "\\\\[A-Z]+[A-Za-z]+\\.[a-z]+"
let regex2 = #"\\[A-Z]+[A-Za-z]+\.[a-z]+"#

自定义字符串插值

SE-0228提案改进了Swift的字符串插值,让其更高效和自由。

代码语言:javascript
复制
struct User {
    var name: String
    var age: Int
}

extension String.StringInterpolation {
    mutating func appendInterpolation(_ value: User) {
        appendInterpolation("My name is \(value.name) and I'm \(value.age)")
    }
}

let user = User(name: "Guybrush Threepwood", age: 33)
print("User details: \(user)")
// User details: My name is Guybrush Threepwood and I'm 33,

// TODO: 更多使用,需要多研究

动态可调用类型

SE-0216 增加了@dynamicCallable属性,来支持方法的动态调用,类似@dynamicMemberLookup

你可以将

代码语言:javascript
复制
struct RandomNumberGenerator {
    func generate(numberOfZeroes: Int) -> Double {
        let maximum = pow(10, Double(numberOfZeroes))
        return Double.random(in: 0...maximum)
    }
}

转变为

代码语言:javascript
复制
@dynamicCallable
struct RandomNumberGenerator {
    func dynamicallyCall(withKeywordArguments args: KeyValuePairs<String, Int>) -> Double {
        let numberOfZeroes = Double(args.first?.value ?? 0)
        let maximum = pow(10, numberOfZeroes)
        return Double.random(in: 0...maximum)
    }
}

let random = RandomNumberGenerator()
let result = random(numberOfZeroes: 0)
  • @dynamicCallable参数
    • 无参数标签withArguments,你可以使用任何遵循ExpressibleByArrayLiteral的类型,例如 数组,数组切片,set等
    • 有参数标签的withKeywordArguments,使用任何遵循ExpressibleByDictionaryLiteral的类型,例如,字典,和key value 对,更多KeyValuePairs可以的看这里,什么是KeyValuePairs?
  • 你可以将其用在结构体,枚举,类和协议上
  • 如果你使用withKeywordArguments而不是withArguments,你仍然按照无参数标签的方式使用,只是key是空字符串。
  • 如果withKeywordArguments或者withArguments标记为抛出错误,调用类型也会抛出错误。
  • 不能在扩展中使用@dynamicCallable
  • 你仍然可以添加属性和方法。

处理未来的枚举值

SE_0192的实现。

有时候枚举的switch中使用default来防治出错,但不会真正的使用,但是如果未来加了新的case,那些处理地方就会遗漏。现在可以添加@unknkow来出触发Xcode的提示。

代码语言:javascript
复制
func showNew(error: PasswordError) {
    switch error {
    case .short:
        print("Your password was too short.")
    case .obvious:
        print("Your password was too obvious.")
    @unknown default:
        print("Your password wasn't suitable.")
    }
}

这样,如果如果代码中,没有处理干净PasswordError (switch block is no longer exhaustive),就会告警.

try?抹平嵌套可选

代码语言:javascript
复制
struct User {
    var id: Int

    init?(id: Int) {
        if id < 1 {
            return nil
        }

        self.id = id
    }

    func getMessages() throws -> String {
        // complicated code here
        return "No messages"
    }
}

let user = User(id: 1)
let messages = try? user?.getMessages()

上面的例子中,Swift 4.2以及之前的,message会是 String??, 这样就不太合理,Swift 5中,就能返回抹平的String?

检查整数是否为偶数

SE-0225添加了, isMultiple(of:)来检查整数是否为偶数, 和if rowNumber % 2 == 0效果一样。

代码语言:javascript
复制
let rowNumber = 4

if rowNumber.isMultiple(of: 2) {
    print("Even")
} else {
    print("Odd")
}

字典compactMapValues()方法

SE-0218,为字典添加了compactMapValues()方法,这个就像结合了,数组compactMap()方法(遍历成员,判断可选的值,然后丢弃nil成员)和字典的mapValues()方法(只转换字典的value)。

代码语言:javascript
复制
let times = [
    "Hudson": "38",
    "Clarke": "42",
    "Robinson": "35",
    "Hartis": "DNF"
]

let finishers1 = times.compactMapValues { Int($0) }
let finishers2 = times.compactMapValues(Int.init)
let people6 = [
    "Paul": 38,
    "Sophie": 8,
    "Charlotte": 5,
    "William": nil
]

let knownAges = people6.compactMapValues { $0 }
print("compactMapValues, \(finishers1), \(finishers2),\(knownAges)")
// compactMapValues, ["Clarke": 42, "Robinson": 35, "Hudson": 38], ["Robinson": 35, "Clarke": 42, "Hudson": 38],["Charlotte": 5, "Sophie": 8, "Paul": 38]

撤回的功能: 带条件的计数

SE-0220, 引入了count(where:)函数,来计算遵循Sequence列表中满足条件成员的个数。

代码语言:javascript
复制
let scores = [100, 80, 85]
let passCount = scores.count { $0 >= 85 }
let pythons = ["Eric Idle", "Graham Chapman", "John Cleese", "Michael Palin", "Terry Gilliam", "Terry Jones"]
let terryCount = pythons.count { $0.hasPrefix("Terry") }

这个功能因为性能问题,被撤回了。


Swift 4.2

CaseIterable协议

SE-0194提议的实现,Swift4.2 增加了CaseIterable协议,能够给枚举的allCases属性自动产生所有的枚举的数组。

代码语言:javascript
复制
enum Pasta: CaseIterable {
    case cannelloni, fusilli, linguine, tagliatelle
}

for shape in Pasta.allCases {
    print("I like eating \(shape).")
}

当然还可以自行实现

代码语言:javascript
复制
enum Car: CaseIterable {
    static var allCases: [Car] {
        return [.ford, .toyota, .jaguar, .bmw, .porsche(convertible: false), .porsche(convertible: true)]
    }

    case ford, toyota, jaguar, bmw
    case porsche(convertible: Bool)
}

警告和错误指令

SE-0196提议的实现。Swift 4.2提供这两个提示,来让Xcode在编译时候作出提示

  • #warning,警告,主要为了提示后续需要处理,Xcode可以编译通过
  • #error, 常用在Library中,强制提示,需要修复,否则不会编译通过。
代码语言:javascript
复制
func encrypt(_ string: String, with password: String) -> String {
    #warning("This is terrible method of encryption")
    return password + String(string.reversed()) + password
}

struct Configuration {
    var apiKey: String {
        #error("Please enter your API key below then delete this line.")
        return "Enter your key here"
    }
}    

还可以和#if配合使用。

代码语言:javascript
复制
#if os(macOS)
#error("MyLibrary is not supported on macOS.")
#endif

动态查找成员

SE-0195提议的实现。Swift 4.2提供了@dynamicMemberLookup的属性,和subscript(dynamicMember:)陪着使用,实现动态的属性的取值。

代码语言:javascript
复制
@dynamicMemberLookup
struct Person5 {
    subscript(dynamicMember member: String) -> String {
        let properties = ["name": "Tylor Swift", "city" : "Nashville"]
        return properties[member, default: ""]
    }
 }

let person5 = Person5()
print("person5.name: \(person5.name)")
print("person5.city: \(person5.city)")
print("person5.favoriteIceCream: \(person5.favoriteIceCream)")
// person5.name: Tylor Swift
// person5.city: Nashville
// person5.favoriteIceCream: 

当然也有类似多态的用法。

代码语言:javascript
复制
@dynamicMemberLookup
struct Person5 {
    subscript(dynamicMember member: String) -> String {
        let properties = ["name": "Tylor Swift", "city" : "Nashville"]
        return properties[member, default: ""]
    }
    
    subscript(dynamicMember member: String) -> Int {
        let properties = ["age": 26, "height": 178]
        return properties[member, default: 0]
    }
 }

let person5 = Person5()
print("person5.age: \(person5.age)")
let age: Int = person5.age
print("person5.age2: \(age)")
// person5.age: 
// person5.age2: 26

注意你需要指定明确指定类型,Swift才能正确使用。

而且如果已经有存在属性,动态属性将不会生效

代码语言:javascript
复制
struct Singer {
    public var name = "Justin Bieber"

    subscript(dynamicMember member: String) -> String {
        return "Taylor Swift"
    }
}

let singer = Singer()
print(singer.name)
// Justin Bieber

@dynamicMemberLookup可以用在协议,结构体,枚举,类,甚至标注为@objc的类,以及它们的继承者。

例如,陪着协议的使用,你可以这样用

代码语言:javascript
复制
@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)

Chris Lattner提议中的例子很有意义,

代码语言:javascript
复制
@dynamicMemberLookup
enum JSON {
   case intValue(Int)
   case stringValue(String)
   case arrayValue(Array<JSON>)
   case dictionaryValue(Dictionary<String, JSON>)

   var stringValue: String? {
      if case .stringValue(let str) = self {
         return str
      }
      return nil
   }

   subscript(index: Int) -> JSON? {
      if case .arrayValue(let arr) = self {
         return index < arr.count ? arr[index] : nil
      }
      return nil
   }

   subscript(key: String) -> JSON? {
      if case .dictionaryValue(let dict) = self {
         return dict[key]
      }
      return nil
   }

   subscript(dynamicMember member: String) -> JSON? {
      if case .dictionaryValue(let dict) = self {
         return dict[member]
      }
      return nil
   }
}

正常使用

代码语言:javascript
复制
let json = JSON.stringValue("Example")
json[0]?["name"]?["first"]?.stringValue

如果用上述的写法

代码语言:javascript
复制
json[0]?.name?.first?.stringValue

有条件地遵循协议的增强

Swift 4.1引入了有条件地遵循协议

代码语言:javascript
复制
extension Array: Purchaseable where Element: Purchaseable {
    func buy() {
        for item in self {
            item.buy()
        }
    }
}

但是在Swift 4.1中,如果你要确定对象是否遵循某个协议,会报错。Swift 4.2 修复了这个问题

代码语言:javascript
复制
let items: Any = [Book(), Book(), Book()]

if let books = items as? Purchaseable {
    books.buy()
}

还有,Swift 内置的类型,可选,数组,字典,区间,如果它们的成员遵循Hashable,那么它们也会自动遵循Hashable

随机数产生和shuffling

SE-0202提议的实现。Swift 4.2提供了原生的随机数方法。意味着你不需要使用arc4random_uniform()或者GameplayKit来实现了。

代码语言:javascript
复制
let randomInt = Int.random(in: 1..<5)
let randomFloat = Float.random(in: 1..<10)
let randomDouble = Double.random(in: 1...100)
let randomCGFloat = CGFloat.random(in: 1...1000)
let randomBool = Bool.random()

SE-0202同样还提议了shuffle()shuffled()

代码语言:javascript
复制
var albums = ["Red", "1989", "Reputation"]

// shuffle in place
albums.shuffle()

// get a shuffled array back
let shuffled = albums.shuffled()

还有randomElement()方法。

代码语言:javascript
复制
if let random = albums.randomElement() {
    print("The random album is \(random).")
}

更简单,安全的Hash

SE-0206的实现,让你更简单的为自建类型使用Hashable协议。

Swift 4.1 能够为遵循Hashable协议的类型自动生成hash值。但是如果你需要自行实现仍然需要写不少代码。

Swift 4.2 引入了Hasher结构,提供了随机种子,和通用的hash函数来简化过程

代码语言:javascript
复制
struct iPad: Hashable {
    var serialNumber: String
    var capacity: Int

    func hash(into hasher: inout Hasher) {
        hasher.combine(serialNumber)
    }
}

let first = iPad(serialNumber: "12345", capacity: 256)
let second = iPad(serialNumber: "54321", capacity: 512)

var hasher = Hasher()
hasher.combine(first)
hasher.combine(second)
let hash = hasher.finalize()

检查列表是否满足条件

SE-0207的实现,提供了allSatisfy()方法来检测数组中所有的元素是否都满足条件。

代码语言:javascript
复制
let scores = [85, 88, 95, 92]
let passed = scores.allSatisfy { $0 >= 85 }

原地字典的元素移除

SE-0197提供一个全新的removeAll(where:)方法,以此来提供一个更高效,会操作原数据的类似filter的方法。

代码语言:javascript
复制
var pythons = ["John", "Michael", "Graham", "Terry", "Eric", "Terry"]
pythons.removeAll { $0.hasPrefix("Terry") }
print(pythons)

Boolean toggling

SE-0199提供了,对Booltoggle()方法,类似

代码语言:javascript
复制
extension Bool {
   mutating func toggle() {
      self = !self
   }
}

Swift 4.2 你可以这样

代码语言:javascript
复制
var loggedIn = false
loggedIn.toggle()

Swift 4.1

EquatableHashable协议

类和结构体做可比较,需要自己手动实现。

代码语言:javascript
复制
struct Person: Equatable {
    var firstName: String
    var lastName: String
    var age: Int
    var city: String

    static func ==(lhs: Person, rhs: Person) -> Bool {
        return lhs.firstName == rhs.firstName && lhs.lastName == rhs.lastName && lhs.age == rhs.age && lhs.city == rhs.city
    }
}

let person1 = Person(firstName: "hicc", lastName: "w", age: 20, city: "shenzhen")
let person2 = Person(firstName: "hicc", lastName: "w", age: 20, city: "shenzhen")
print("person1 1 == person2 : \(person1 == person2)")
// person1 1 == person2 : true

Swift 4.1 提供了Equatable的协议,它会自动的生成==方法。

当然你还是可以自己实现==方法(例如,业务有id之类的属性)。

还有之前实现一个对象的hash值也是一件麻烦的事情,你可能需要手动实现类似:

代码语言:javascript
复制
var hashValue: Int {
    return firstName.hashValue ^ lastName.hashValue &* 16777619
}

Swift 4.1 提供了Hashable的协议,可以自动生成hashValue,你也还是可以自行实现。

代码语言:javascript
复制
struct Person2: Equatable, Hashable {
    var firstName: String
    var lastName: String
    var age: Int
    var city: String
}

let person11 = Person2(firstName: "hicc", lastName: "w", age: 20, city: "shenzhen")
let person22 = Person2(firstName: "hicc", lastName: "w", age: 20, city: "shenzhen")
print("person11 1 == person22 : \(person11 == person22), \(person11.hashValue)")
// person11 1 == person22 : true, 5419288582170212869

Codable协议,Key值转化策略

Swift 4提供了很方便的Codable协议,但是它使用下划线snake_case而不是驼峰式的方式来转化Key,不太自由。

Swift 4.1 中针对这种情况,提供了keyDecodingStrategy,以及keyEncodingStrategy属性(默认.useDefaultKeys)来解决这些问题。

代码语言:javascript
复制
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase

do {
    let macs = try decoder.decode([Mac].self, from: jsonData)
    print(macs)
} catch {
    print(error.localizedDescription)
}

let encoder = JSONEncoder()
encoder.keyEncodingStrategy = .convertToSnakeCase
let encoded = try encoder.encode(someObject)

有条件地遵循协议

Swift 4.1 实现了SE-0143的提议,容许你类型在某下情况下才遵循某个协议。

代码语言:javascript
复制
extension Array: Purchaseable where Element: Purchaseable {
   func buy() {
      for item in self {
         item.buy()
      }
   }
}

这样会让你的代码,更加的安全。如下代码Swift中会拒绝编译,因为其未遵循Coodable协议.

代码语言:javascript
复制
import Foundation

struct Person {
   var name = "Taylor"
}

var people = [Person()]
var encoder = JSONEncoder()
try encoder.encode(people)

关联类型中的递归限制

Swift 4.1实现了SE-0157提议,在递归协议中,关联类型可以被定义它的协议所限制。

代码语言:javascript
复制
protocol Employee {
   associatedtype Manager: Employee
   var manager: Manager? { get set }
}

// TODO: 现在感受不太清楚,后续有深入了解在补充。

canImport函数

SE-0075提议的实现。Swift 4.1引入了canImport函数,让你可以检查某个模块能否被导入。

代码语言:javascript
复制
#if canImport(SpriteKit)
   // this will be true for iOS, macOS, tvOS, and watchOS
#else
   // this will be true for other platforms, such as Linux
#endif

之前还有类似的方法

代码语言:javascript
复制
#if !os(Linux)
   // Matches macOS, iOS, watchOS, tvOS, and any other future platforms
#endif

#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
   // Matches only Apple platforms, but needs to be kept up to date as new platforms are added
#endif

targetEnvironment函数

SE-0190提议的实现,Swift 4.1 提供了targetEnvironment函数,来检测是模拟器还是真实的硬件。

代码语言:javascript
复制
#if targetEnvironment(simulator)
   // code for the simulator here
#else
   // code for real devices here
#endif

flatMap改名为compactMap

flatMap之前一个很有用的作用是能够过滤数组中为nil的元素,Swift 4.2重命名为指意明确,更强大的compactMap

代码语言:javascript
复制
let array = ["1", "2", "Fish"]
let numbers = array.compactMap { Int($0) }
// [1, 2]

Swift 4.0

Coodable协议

Swift 4之前使用NSCoding来做encoding和decoding的事情,但是需要一些模版代码,也容易出错,Swift 4中 Coodable协议就是为这个而存在。

使用起来简单到不可思议。

代码语言:javascript
复制
struct Language: Codable {
    var name: String
    var version: Int
}

let swift = Language(name: "Swift", version: 4)

完整的使用

代码语言:javascript
复制
let encoder = JSONEncoder()
if let encoded = try? encoder.encode(swift) {
    if let json = String(data: encoded, encoding: .utf8) {
        print("swift strng\(json)")
    }
    
    let decoder = JSONDecoder()
    if let decoded = try? decoder.decode(Language.self, from: encoded) {
        print("Swift name: \(decoded.name)")
    }
}

多行字符串字面量

跨越多行的字符串可以使用"""来包裹。

代码语言:javascript
复制
let quotation = """
The White Rabbit put on his spectacles. "Where shall I begin,
please your Majesty?" he asked.

"Begin at the beginning," the King said gravely, "and go on
till you come to the end; then stop."
"""

改进Key-value编码中的keypaths

keypaths是指对属性的引用而不去真正读取属性的值。

代码语言:javascript
复制
struct Crew {
    var name: String
    var rank: String
}

struct Starship {
    var name: String
    var maxWarp: Double
    var captain: Crew
}

let janeway = Crew(name: "Kathryn Janeway", rank: "Captain")
let voyager = Starship(name: "Voyager", maxWarp: 9.975, captain: janeway)


let nameKeyPath = \Starship.name
let maxWarpKeyPath = \Starship.maxWarp
let captainName = \Starship.captain.name

let starshipName = voyager[keyPath: nameKeyPath]
let starshipMaxWarp = voyager[keyPath: maxWarpKeyPath]
let starshipCaptain = voyager[keyPath: captainName]

print("starshipName \(starshipName),\(starshipCaptain)")
// starshipName Voyager, Kathryn Janeway

改进字典函数

Swift 4改进了字典的诸多函数。

  • filter返回的是个字典
  • map 返回的仍然是数组
  • mapValues,返回的则是字典
  • grouping初始化方法,可以将数组处理成字典
  • default赋值和取值会比较方便。
代码语言:javascript
复制
let cities = ["Shanghai": 24_256_800, "Karachi": 23_500_000, "Beijing": 21_516_000, "Seoul": 9_995_000];
let massiveCities = cities.filter { $0.value > 10_000_000 }
let populations = cities.map { $0.value * 2 }
let roundedCities = cities.mapValues { "\($0 / 1_000_000) million people" }
let groupedCities = Dictionary(grouping: cities.keys) { $0.first! }
let groupedCities2 = Dictionary(grouping: cities.keys) { $0.count }

var favoriteTVShows = ["Red Dwarf", "Blackadder", "Fawlty Towers", "Red Dwarf"]
var favoriteCounts = [String: Int]()

for show in favoriteTVShows {
    favoriteCounts[show, default: 0] += 1
}

print("dic\(massiveCities),\n\(populations),\n\(roundedCities),\n\(groupedCities),\n\(groupedCities2),\n\(favoriteCounts)")
// dic["Shanghai": 24256800, "Beijing": 21516000, "Karachi": 23500000],
// [43032000, 47000000, 19990000, 48513600],
///["Beijing": "21 million people", "Karachi": "23 million people", "Seoul": "9 million people", "Shanghai": "24 million people"],
// ["S": ["Seoul", "Shanghai"], "B": ["Beijing"], "K": ["Karachi"]],
// [8: ["Shanghai"], 5: ["Seoul"], 7: ["Beijing", "Karachi"]],
// ["Blackadder": 1, "Fawlty Towers": 1, "Red Dwarf": 2]

字符串又变成了Collection类型

字符串是Collection类型,这样就有了诸多便利的方法。

代码语言:javascript
复制
let quote = "It is a truth universally acknowledged that new Swift versions bring new features."
let reversed = quote.reversed()

for letter in quote {
    print(letter)
}

单侧区间

Swift 4 支持了单侧区间, 缺失的一边为0或者为集合的尽头

代码语言:javascript
复制
let characters = ["Dr Horrible", "Captain Hammer", "Penny", "Bad Horse", "Moist"]
let bigParts = characters[..<3]
let smallParts = characters[3...]
print(bigParts)
print(smallParts)
// ["Dr Horrible", "Captain Hammer", "Penny"]
// ["Bad Horse", "Moist"]

Swift 3.1

扩展限制的优化

Swift支持对扩展做限制。

代码语言:javascript
复制
extension Collection where Iterator.Element: Comparable {
    func lessThanFirst() -> [Iterator.Element] {
        guard let first = self.first else { return [] }
        return self.filter { $0 < first }
    }
}

let items = [5, 6, 10, 4, 110, 3].lessThanFirst()
print(items)
代码语言:javascript
复制
extension Array where Element: Comparable {
    func lessThanFirst() -> [Element] {
        guard let first = self.first else { return [] }
        return self.filter { $0 < first }
    }
}

let items = [5, 6, 10, 4, 110, 3].lessThanFirst()
print(items)

上述3.0的对扩展的限制都是通过协议实现。Swift 3.1 支持使用类型来限制。

代码语言:javascript
复制
extension Array where Element == Int {
    func lessThanFirst() -> [Int] {
        guard let first = self.first else { return [] }
        return self.filter { $0 < first }
    }
}

let items = [5, 6, 10, 4, 110, 3].lessThanFirst()
print(items)

嵌套类型支持泛型

Swift 3.1支持了嵌套类型中使用泛型。

代码语言:javascript
复制
struct Message<T> {
    struct Attachment {
        var contents: T
    }

    var title: T
    var attachment: Attachment
}

序列(Sequences)协议增加了prefix(while:), drop(while:)两个方法

  • prefix(while:): 遍历所有元素,直到遇到不满足条件的元素 ,并且返回满足的元素
  • drop(while:): 就是返回 prefix(while:)相反的就好。
代码语言:javascript
复制
let names = ["Michael Jackson", "Michael Jordan", "Michael Caine", "Taylor Swift", "Adele Adkins", "Michael Douglas"]
let prefixed = names.prefix { $0.hasPrefix("Michael") }
print(prefixed)
let dropped = names.drop { $0.hasPrefix("Michael") }
print(dropped)

Swift 3.0

函数调用必须使用参数标签

Swift特点是函数可以分别制定参数标签(argument label)和参数名称(parameter name)

代码语言:javascript
复制
func someFunction(argumentLabel parameterName: Int) {
}
// 使用必须带上参数标签
someFunction(argumentLabel: 1)

// 如果不指定,参数名称可以作为菜参数标签
func someFunction(firstParameterName: Int, secondParameterName: Int) {
}
someFunction(firstParameterName: 1, secondParameterName: 2)

如果你不想使用参数标签,可以使用_代替

代码语言:javascript
复制
func someFunction(_ firstParameterName: Int, secondParameterName: Int) {
}
someFunction(1, secondParameterName: 2)

移除多余代码

主要是一些内置对象,以及和平台相关的精简,让代码更加易读。

代码语言:javascript
复制
// Swift 2.2
let blue = UIColor.blueColor()
let min = numbers.minElement()
attributedString.appendAttributedString(anotherString)
names.insert("Jane", atIndex: 0)
UIDevice.currentDevice()
// Swift 3
let blue = UIColor.blue
let min = numbers.min()
attributedString.append(anotherString)
names.insert("Jane", at: 0)
UIDevice.current

以及

代码语言:javascript
复制
// 第一行是Swift 2.2
// 迪尔汗是Swift 3
"  Hello  ".stringByTrimmingCharactersInSet(.whitespaceAndNewlineCharacterSet())
"  Hello  ".trimmingCharacters(in: .whitespacesAndNewlines)

"Taylor".containsString("ayl")
"Taylor".contains("ayl")

"1,2,3,4,5".componentsSeparatedByString(",")
"1,2,3,4,5".components(separatedBy: ",")

myPath.stringByAppendingPathComponent("file.txt")
myPath.appendingPathComponent("file.txt")

"Hello, world".stringByReplacingOccurrencesOfString("Hello", withString: "Goodbye")
"Hello, world".replacingOccurrences(of: "Hello", with: "Goodbye")

"Hello, world".substringFromIndex(7)
"Hello, world".substring(from: 7)

"Hello, world".capitalizedString
"Hello, world".capitalized

以及, lowercaseString -> lowercased()uppercaseString ->uppercased()

代码语言:javascript
复制
dismissViewControllerAnimated(true, completion: nil)
dismiss(animated: true, completion: nil)
dismiss(animated: true)
prepareForSegue()
override func prepare(for segue: UIStoryboardSegue, sender: AnyObject?)

枚举和属性从大驼峰替换为小驼峰

正如标题说的,一方面这是Swift推荐的用法,另外就是内置对象的变化

代码语言:javascript
复制
UIInterfaceOrientationMask.Portrait // old
UIInterfaceOrientationMask.portrait // new

NSTextAlignment.Left // old
NSTextAlignment.left // new

SKBlendMode.Replace // old
SKBlendMode.replace // new

还有就是Swift可选类型是通过枚举来实现的

代码语言:javascript
复制
enum Optional {
    case None
    case Some(Wrapped)
}

如果使用.Some来处理可选,也需要更改

代码语言:javascript
复制
for case let .some(datum) in data {
    print(datum)
}

for case let datum? in data {
    print(datum)
}

更swift地改进C函数

大体来说就是让C函数使用更加的Swift

代码语言:javascript
复制
// Swift 2.2
let ctx = UIGraphicsGetCurrentContext()

let rectangle = CGRect(x: 0, y: 0, width: 512, height: 512)
CGContextSetFillColorWithColor(ctx, UIColor.redColor().CGColor)
CGContextSetStrokeColorWithColor(ctx, UIColor.blackColor().CGColor)
CGContextSetLineWidth(ctx, 10)
CGContextAddRect(ctx, rectangle)
CGContextDrawPath(ctx, .FillStroke)

UIGraphicsEndImageContext()

// Swift 3
if let ctx = UIGraphicsGetCurrentContext() {
    let rectangle = CGRect(x: 0, y: 0, width: 512, height: 512)
    ctx.setFillColor(UIColor.red.cgColor)
    ctx.setStrokeColor(UIColor.black.cgColor)
    ctx.setLineWidth(10)
    ctx.addRect(rectangle)
    ctx.drawPath(using: .fillStroke)

    UIGraphicsEndImageContext()
}

以及

代码语言:javascript
复制
// 第一行是Swift 2.2
// 第二行是Swift 3
CGAffineTransformIdentity
CGAffineTransform.identity

CGAffineTransformMakeScale(2, 2)
CGAffineTransform(scaleX: 2, y: 2)

CGAffineTransformMakeTranslation(128, 128)
CGAffineTransform(translationX: 128, y: 128)

CGAffineTransformMakeRotation(CGFloat(M_PI))
CGAffineTransform(rotationAngle: CGFloat(M_PI))

名次和动词

这部分属于Swift更加语义化的改进,到现在5.1的时候一直在改进,目前官网最近的规范Swift.org - API Design Guidelines方法的部分是:

  • 按照它们的副作用来命名函数和方法
    • 无副作用的按照名次来命名。x.distance(to: y)i.successor()
    • 有副作用的按照动词来命名。print(x)x.sort()x.append(y)
    • 有修改和无修改命名
      • 动词的方法中,无修改的使用过去时ed(通常是,不修改原数据,而是返回新的),有修改的使用现在时ing
      • 名词的方法中,无修改的使用名词,有修改的前面加上from
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • toc
  • Swift 5.1
  • Swift 5.0
    • Result类型
      • Raw string
        • 自定义字符串插值
          • 动态可调用类型
            • 处理未来的枚举值
              • 从try?抹平嵌套可选
                • 检查整数是否为偶数
                  • 字典compactMapValues()方法
                    • 撤回的功能: 带条件的计数
                    • Swift 4.2
                      • CaseIterable协议
                        • 警告和错误指令
                          • 动态查找成员
                            • 有条件地遵循协议的增强
                              • 随机数产生和shuffling
                                • 更简单,安全的Hash
                                  • 检查列表是否满足条件
                                    • 原地字典的元素移除
                                      • Boolean toggling
                                      • Swift 4.1
                                        • Equatable和Hashable协议
                                          • Codable协议,Key值转化策略
                                            • 有条件地遵循协议
                                              • 关联类型中的递归限制
                                                • canImport函数
                                                  • targetEnvironment函数
                                                    • flatMap改名为compactMap
                                                    • Swift 4.0
                                                      • Coodable协议
                                                        • 多行字符串字面量
                                                          • 改进Key-value编码中的keypaths
                                                            • 改进字典函数
                                                              • 字符串又变成了Collection类型
                                                                • 单侧区间
                                                                • Swift 3.1
                                                                  • 扩展限制的优化
                                                                    • 嵌套类型支持泛型
                                                                      • 序列(Sequences)协议增加了prefix(while:), drop(while:)两个方法
                                                                      • Swift 3.0
                                                                        • 函数调用必须使用参数标签
                                                                          • 移除多余代码
                                                                            • 枚举和属性从大驼峰替换为小驼峰
                                                                              • 更swift地改进C函数
                                                                                • 名次和动词
                                                                                领券
                                                                                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档