Có gì mới trong Swift 4.1?
Conditional Conformance Đây là một tính năng mạnh mẽ giúp mã của bạn linh hoạt hơn. Bạn có thể xem cách nó hoạt động với một vài ví dụ. Conditional Conformance trong thư viện chuẩn Trong Swift 4, bạn có thể so sánh các Mảng, Dictionary và các tùy chọn miễn là các phần tử của chúng là ...
Conditional Conformance
Đây là một tính năng mạnh mẽ giúp mã của bạn linh hoạt hơn. Bạn có thể xem cách nó hoạt động với một vài ví dụ.
Conditional Conformance trong thư viện chuẩn
Trong Swift 4, bạn có thể so sánh các Mảng, Dictionary và các tùy chọn miễn là các phần tử của chúng là Equatable. Điều này hoàn toàn tốt cho các tình huống cơ bản như:
// Arrays of Int let firstArray = [1, 2, 3] let secondArray = [1, 2, 3] let sameArray = firstArray == secondArray // Dictionaries with Int values let firstDictionary = ["Cosmin": 10, "George": 9] let secondDictionary = ["Cosmin": 10, "George": 9] let sameDictionary = firstDictionary == secondDictionary // Comparing Int? let firstOptional = firstDictionary["Cosmin"] let secondOptional = secondDictionary["Cosmin"]ng let sameOptional = firstOptional == secondOptional
Sử dụng toán tử == để kiểm tra giống nhau trong các ví dụ này, vì Int là Equatable trong Swift 4. Tuy nhiên, so sánh các phần tử optional là một tình huống phổ biến mà bạn có thể gặp phải với Swift 4 vì các phần tử optional không phù hợp với Equatable. Swift 4.1 khắc phục vấn đề này bằng cách sử dụng Conditional Conformance, cho phép các kiểu optional với các kiểu Equatable cơ bản được so sánh:
// Array of Int? let firstArray = [1, nil, 2, nil, 3, nil] let secondArray = [1, nil, 2, nil, 3, nil] let sameArray = firstArray == secondArray // Dictionary with Int? values let firstDictionary = ["Cosmin": 10, "George": nil] let secondDictionary = ["Cosmin": 10, "George": nil] let sameDictionary = firstDictionary == secondDictionary // Comparing Int?? (Optional of Optional) let firstOptional = firstDictionary["Cosmin"] let secondOptional = secondDictionary["Cosmin"] let sameOptional = firstOptional == secondOptional
Int? is Equatable in Swift 4.1, so the == operator works for [Int?], [String: Int?] and Int??. Một vấn đề tương tự đã được giải quyết khi so sánh các mảng của mảng (ví dụ [[Int]]). Trong Swift 4, bạn chỉ có thể so sánh các mảng của các Set (ví dụ: [Set <Int>]), vì các Set phù hợp với Equatable. Swift 4.1 giải quyết điều này, vì các mảng (và Dictionary) là Equatable miễn là các giá trị bên trong của chúng cũng vậy.
let firstArrayOfSets = [Set([1, 2, 3]), Set([1, 2, 3])] let secondArrayOfSets = [Set([1, 2, 3]), Set([1, 2, 3])] // Will work in Swift 4 and Swift 4.1 // since Set<Int> is Equatable firstArrayOfSets == secondArrayOfSets let firstArrayOfArrays = [[1, 2, 3], [3, 4, 5]] let secondArrayOfArrays = [[1, 2, 3], [3, 4, 5]] // Caused an error in Swift 4, but works in Swift 4.1 // since Arrays are Equatable in Swift 4.1 firstArrayOfArrays == secondArrayOfArrays
Nói chung, Optional, Array và Dictionary của Swift 4.1 phù hợp với Equatable và Hashable bất cứ khi nào các giá trị hoặc phần tử cơ bản của chúng phù hợp với các giao thức này. Đây là cách conditional conformance hoạt động trong thư viện chuẩn. Tiếp theo, bạn sẽ thực hiện nó trong code.
Conditional conformance trong code
Bạn sẽ sử dụng Conditional conformance để tạo ra các nhạc cụ của riêng bạn. Thêm khối mã sau vào cuối playground để bắt đầu:
// 1 class LeadInstrument: Equatable { let brand: String init(brand: String) { self.brand = brand } func tune() -> String { return "Standard tuning." } static func ==(lhs: LeadInstrument, rhs: LeadInstrument) -> Bool { return lhs.brand == rhs.brand } } // 2 class Keyboard: LeadInstrument { override func tune() -> String { return "Keyboard standard tuning." } } // 3 class Guitar: LeadInstrument { override func tune() -> String { return "Guitar standard tuning." } }
Bạn thực hiện theo những bước sau: 1. LeadInstrument phù hợp với Equatable. Nó có một brand nhất định và một method có tên là tune() mà cuối cùng bạn sẽ sử dụng tune để điều chỉnh nhạc cụ. 2. Bạn override tune() trong Keyboard để trả về điều chỉnh chuẩn của Keyboard. 3. Bạn làm điều tương tự với Guitar.
Tiếp theo, bạn khai báo band:
// 1 class Band<LeadInstrument> { let name: String let lead: LeadInstrument init(name: String, lead: LeadInstrument) { self.name = name self.lead = lead } } // 2 extension Band: Equatable where LeadInstrument: Equatable { static func ==(lhs: Band<LeadInstrument>, rhs: Band<LeadInstrument>) -> Bool { return lhs.name == rhs.name && lhs.lead == rhs.lead } }
Dưới đây, bạn thực hiện từng bước: 1. Bạn tạo một lớp có tên là Band với kiểu generic - LeadInstrument. Mỗi ban nhạc có một tên duy nhất và công cụ chính. 2. Bạn sử dụng where để hạn chế Band để phù hợp với Equatable miễn là LeadInstrument làm.
Tiếp theo, xác định các ban nhạc yêu thích của bạn và so sánh chúng:
// 1 let rolandKeyboard = Keyboard(brand: "Roland") let rolandBand = Band(name: "Keys", lead: rolandKeyboard) let yamahaKeyboard = Keyboard(brand: "Yamaha") let yamahaBand = Band(name: "Keys", lead: yamahaKeyboard) let sameBand = rolandBand == yamahaBand // 2 let fenderGuitar = Guitar(brand: "Fender") let fenderBand = Band(name: "Strings", lead: fenderGuitar) let ibanezGuitar = Guitar(brand: "Ibanez") let ibanezBand = Band(name: "Strings", lead: ibanezGuitar) let sameBands = fenderBand == ibanezBand
Trong đoạn mã này, bạn tạo hai Keyboards và Guitars cùng với các Bands thích hợp của chúng. Sau đó bạn so sánh trực tiếp các ban nhạc, nhờ vào sự phù hợp có điều kiện mà bạn đã xác định trước đó.
Conditional conformance trong JSON parsing
Array, Dictionary, Set và các optional phù hợp với Codable nếu các phần tử của chúng tuân theo Codable trong Swift 4.1. Thêm đoạn mã sau vào playground của bạn để thử điều này:
struct Student: Codable, Hashable { let firstName: String let averageGrade: Int } let cosmin = Student(firstName: "Cosmin", averageGrade: 10) let george = Student(firstName: "George", averageGrade: 9) let encoder = JSONEncoder() // Encode an Array of students let students = [cosmin, george] do { try encoder.encode(students) } catch { print("Failed encoding students array: (error)") } // Encode a Dictionary with student values let studentsDictionary = ["Cosmin": cosmin, "George": george] do { try encoder.encode(studentsDictionary) } catch { print("Failed encoding students dictionary: (error)") } // Encode a Set of students let studentsSet: Set = [cosmin, george] do { try encoder.encode(studentsSet) } catch { print("Failed encoding students set: (error)") } // Encode an Optional Student let optionalStudent: Student? = cosmin do { try encoder.encode(optionalStudent) } catch { print("Failed encoding optional student: (error)") }
Bạn sử dụng mã này để mã hóa [Student], [String: Student], Set<Student> và Student?. Điều này hoạt động trơn tru trong Swift 4.1 vì Student là Codable, điều này làm cho các loại bộ sưu tập này phù hợp với nó.
Chuyển đổi giữa trường hợp Camel và Snake Case trong quá trình mã hóa JSON
Swift 4.1 cho phép bạn chuyển đổi các thuộc tính CamelCase thành các khóa snake_case trong khi mã hóa JSON
var jsonData = Data() encoder.keyEncodingStrategy = .convertToSnakeCase encoder.outputFormatting = .prettyPrinted do { jsonData = try encoder.encode(students) } catch { print(error) } if let jsonString = String(data: jsonData, encoding: .utf8) { print(jsonString) }
Khi tạo bộ mã hóa, bạn đặt keyEncodingStrategy thành .convertToSnakeCase. Nhìn vào giao diện console của bạn, bạn sẽ thấy:
var studentsInfo: [Student] = [] let decoder = JSONDecoder() decoder.keyDecodingStrategy = .convertFromSnakeCase do { studentsInfo = try decoder.decode([Student].self, from: jsonData) } catch { print(error) } for studentInfo in studentsInfo { print("(studentInfo.firstName) (studentInfo.averageGrade)") }
Lần này, bạn đặt keyDecodingStrategy thành .convertFromSnakeCase.
Equatable và Hashable Protocols Conformance
Swift 4 yêu cầu bạn viết mã boilerplate để tạo các cấu trúc phù hợp với Equatable và Hashable:
struct Country: Hashable { let name: String let capital: String 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 } }
Sử dụng mã này, bạn đã triển khai thực hiện == (lhs: rhs