Skip to content
  • Home
  • Code
  • iOS & Swift
  • Combine
  • RxSwift
  • SwiftUI
  • Flutter & Dart
  • Tutorials
  • Art
  • Blog
Fx Studio
  • Home
  • Code
  • iOS & Swift
  • Combine
  • RxSwift
  • SwiftUI
  • Flutter & Dart
  • Tutorials
  • Art
  • Blog
Written by chuotfx on July 2, 2020

Swift 5.3 có gì mới?

iOS & Swift

Contents

  • Chuẩn bị
  • 1. Multi-pattern catch clauses
  • 2. Multiple trailing closures
  • 3. Synthesized Comparable conformance for enums
  • 4. self is no longer required in many places
  • 5. Type-Based Program Entry Points
  • 6. where clauses on contextually generic declarations
  • 7. Enum cases as protocol witnesses
  • 8. Refine didSet Semantics
  • 9. A new Float16 type
  • Tham khảo

Chào bạn đến với Fx Studio. Vào ngày 20/6/2020, tại sự kiện WWDC 2020 của Apple đã ra mắt phiên bản mới nhất của ngôn ngữ Swift. Đó là phiên bản Swift 5.3. Bây giờ, chúng ta sẽ tìm hiểu có những điểm nào mới trong Swift 5.3.

Lưu ý, bài viết này chỉ mang tính chất liệt kê những điểm thay đổi mới. Không trình bày hay giải thích ý nghĩa của chúng.

Chuẩn bị

    • Xcode 12
    • Playground
    • Swift 5.3

Bạn cần chuẩn bị thêm một ít kiến thức cơ bản như là:

    • Basic Swift trong 10 phút
    • Lập trình iOS cho mọi người

1. Multi-pattern catch clauses

 Đố anh bắt được em!

Ở các phiên bản trước, thì mỗi catch bạn chỉ được phép bắt 1 loại lỗi mà thôi. Nhưng đôi khi các anh lập trình viên lại lười xử lý các lỗi riêng biệt đó. Và Apple đã nghe lời thỉnh cầu của các dev, vì vậy tính năng này được ra mắt. Mục đích duy nhất là nhóm các lỗi lại với nhau, khi chúng nó có cùng chung 1 xử lý. Hoặc để cho mấy anh dev có cơ hội lười mà thôi.

Code ví dụ:

  • Khai báo 1 error enum cho xịn sò
enum TemperatureError: Error {
    case tooCold, tooHot
}
  • Viết một function trả về nhiệt độ một cách ngẫu nhiên
func getReactorTemperature() -> Int {
  Int.random(in: 0...100)
}
  • Xử lý việc nhận được nhiệt độ đó, pha xử lý này được xem là kinh điển. Vì nó sẽ ném (throw) lỗi cho thèn nào gọi nó mà tiếp quản tiếp.
func checkReactorOperational() throws -> String {
    let temp = getReactorTemperature()

    if temp < 10 {
        throw TemperatureError.tooCold
    } else if temp > 90 {
        throw TemperatureError.tooHot
    } else {
        return "OK"
    }
}
  • Sử dụng nào!
do {
    let result = try checkReactorOperational()
    print("Result: \(result)")
} catch TemperatureError.tooHot, TemperatureError.tooCold {
    print("Shut down the reactor!")
} catch {
    print("An unknown error occurred.")
}

Chú ý 2 trường hợp là tooHot và tooCold được dùng cùng trong 1 catch.

2. Multiple trailing closures

Giúp các thanh niên chuyên dùng  closure bớt phê cần đi.

Ví dụ ta có một function như sau:

func add(a: Int, b: Int, minResult: (Int) -> Void, maxResult: (Int) -> Void) {
  let minNumber = min(a,b)
  let maxNumber = max(a,b)
  
  minResult(minNumber)
  maxResult(maxNumber)
}

Nếu như bạn đam mê dùng closure thì có một vấn đề là: khi Xcode suggestion cho bạn và bạn chỉ biết enter và gõ code. Thì sử dụng function trên như sau (với Xcode 11 và Swift 5.2 trở về trước)

add(a: 10, b: 20, minResult: { (min) in
  print("Min : \(min)")
}) { (max) in
  print("Max : \(max)")
}

Loạn não khi 2 closure được đặt cuối cùng:

  • 1 cái sẽ có tên đối số, là minResult
  • 1 cái sẽ bị lượt bỏ đi, vì nó là đứa cuối cùng trong danh sách tham số

Hậu quả là: “đọc code kiểu này nhiều thì loạn mắt”. Do đó, Swift 5.3 đã cải tiến như sau:

add(a: 10, b: 20) { (min) in
  print("Min : \(min)")
} maxResult: { (max) in
  print("Max : \(max)")
}

Bạn sẽ thấy:

  • Nhận ra là cách mới sẽ thêm các closure ở phía sau một cách xin sò hơn
  • Đỡ phải có dấu , để phân biệt giữa cách closure với nhau
  • Closure sau sẽ ở sau dấu { và trên cùng 1 hàng với dấu đó
  • Hiệu quả trong SwiftUI
  • Lâu dần bạn sẽ quên mịa cách viết hàm mất đó

3. Synthesized Comparable conformance for enums

Kỉ nguyên bá đạo của Enum sẽ bắt đầu từ đây.

Bạn có thể so sánh các số Int, Float, Double … với nhau. Vì tụi nó có thể so sánh với nhau được. Còn với các struct, class, các đối tượng của nó muốn như vậy, thì phải implement protocol Comparable. Tất nhiên, Enum được loại trừ ra như 1 quy luật tất yếu của cuộc sống. Khi bạn cố implement Comparable cho Enum thì bạn phải viết lại các toán tử (operator).

Quá cực!

Và Swift 5.3 đã cứu bạn thêm một lần nữa. Bây giờ, bạn có thể implement Comparable cho Enum một cách vô tư mà không cần thiết phải viết thêm gì hết.

Ví dụ cơ bản sau:

enum Size: Comparable {
    case small
    case medium
    case large
    case extraLarge
}

let shirtSize = Size.small
let personSize = Size.large

if shirtSize < personSize {
    print("That shirt is too small")
}

Bạn có thể dùng các toán tử so sánh như <, > để so sánh trực tiếp các Enum với nhau. Và niềm vui lại nhân đôi, khi mục đích chính là bạn có thể dùng các hàm sorted của hệ thống. Để sắp sếp đám Enum rắc rối kia.

Cái này thì nhiều ngôn ngữ lập trình khác phải ghen tỵ thôi. Ahihi!

enum WorldCupResult: Comparable {
    case neverWon
    case winner(stars: Int)
}

// cho các đội, khác nhau theo từng case hoặc giá trị trong mỗi case
let americanMen = WorldCupResult.neverWon
let americanWomen = WorldCupResult.winner(stars: 4)
let japaneseMen = WorldCupResult.neverWon
let japaneseWomen = WorldCupResult.winner(stars: 1)

// tạo 1 mãng
let teams = [americanMen, americanWomen, japaneseMen, japaneseWomen]

// dùng hàm mặc định
let sortedByWins = teams.sorted()

// xem kết quả
print(sortedByWins)

4. self is no longer required in many places

Đối tượng tiêu diệt mới là self.

Nhiều bạn chắc đã từng gặp rất nhiều lần việc phải thêm từ khoá là self. Để xác định cụ thể các thuộc tính và phương thức của class trong các closure. Nhất là chúng nó bất đồng bộ. Mà đôi khi bạn biết rằng, tụi nó cùng chung cấu trúc với nhau.

Với Swift 5.3, sẽ giảm đi cho bạn công việc này. Nó tự động suy đoán để biết được lúc nào cần hay không cần  self trong code.

Ví dụ minh hoạ

class Test {
    var x = 0
    func execute(_ work: @escaping () -> Void) {
        work()
    }
  
    func method() {
      execute(inc) // self is captured, but no error!

      execute { inc() } // error

      execute {
        self.x += 1 // with Swift 5.2
      }

    }
  
    func inc() {
        x += 1
    }
}

Trong ví dụ trên,

  • Trường hợp 1 thì mình sẽ bỏ qua con trỏ self trong việc gán hàm inc cho execute. Vì Swift sẽ suy luận được việc inc cùng chung cấu trúc với excute (mình không chắc chắn ở đâu lắm)
  • Sẽ báo lỗi, vì bây giờ mình cần thực thi inc trong excute
  • Cái cuối sẽ là các truyền thống, cần phải có con trỏ self để truy cập tới x

Nó không phải là weak self như truyền thuyết, nhưng phải cần thêm [self] ở closure để capture self.

Một cách để dùng oke hơn và giúp Swift xác định rõ self, thì như sau:

execute { [self] in
        x += 1 // OKE with Swift 5.3
      }

5. Type-Based Program Entry Points

Tạm biệt main.swift.

Không biết đây có chứa thuyết âm mưu nào từ Apple hay không. Khi bỏ đi vị thế độc tôn của file main.swift. Và khi chạy một chương trình, thì con trỏ đầu tiên sẽ kích hoạt với bất kì class nào, miễn là có khai báo @main và ở bất kì file *.swift nào.

Có thể có nhiều bạn dev iOS không biết tới nó, vì @main thường ẩn đi và bạn không bao giờ làm việc với nó, hay thấy được main.swift.  Nhưng cái tương tự như nó là : @UIApplicationMain hay @NSApplicationMain (bạn tìm tụi nó ở file AppDelegate.swift trong iOS Project).

Còn với tính năng mới này, thì rất hay cho các bạn viết các ứng dụng như command-line hoặc 1 một nền tảng mới của Swift mà Apple đang ấp ủ.

Ví dụ nào, tạo 1 project trên MacOS đơn giản nha:

  • Bạn thấy main.swift
  • Mọi code sẽ bắt đầu ở đó
  • Thực thi chương trình và thấy được kết quả ở console.

Xoá file main.swift và thêm Main mới của bạn như sau:

Với @main thì xác định class/struct nào sẽ được khởi tạo và tự động thực thi. Trong đó, phải có hàm static func main() được cài đặt. Ngoài ra, ta có một số lưu ý sau:

  • Không dùng @main trong file main.swift
  • Không có nhiều cái @main trong 1 project hay 1 file (nếu chương trình chỉ có 1 file)
  • Dùng ở base class và nó không được kế thừa hay có subclass

6. where clauses on contextually generic declarations

Anh where bá đạo.

Trước đây, với Generic thì chúng ta không sử dụng được câu lệnh where. Swift 5.3 đã thêm tính năng dùng câu lệnh where với khai báo Generic.

Lợi điểm của việc này là bạn có thể sử dụng nó cho hàm có sẵn trong hệ thống (như: sorted() ). Implement với các protocol như: Equatable, Comparable

struct Stack<Element> {
    private var array = [Element]()

    mutating func push(_ obj: Element) {
        array.append(obj)
    }

    mutating func pop() -> Element? {
        array.popLast()
    }
}

extension Stack {
    func sorted() -> [Element] where Element: Comparable {
        array.sorted()
    }
}

7. Enum cases as protocol witnesses

Enum bất diệt! Giờ ảnh không ngại bất cứ bố con thèn nào nữa rồi.

Lại là câu chuyên trước đây, khi bạn implement 1 Protocol vào 1 enum thì:

  • Phải định nghĩa lại hết tất cả
  • Với Struct và Class, có ý nghĩa hơn enum nhiều khi các thuộc tính và phương thức trong Protocol là kiểu static
  • Sử dụng tên Class/Struct để truy cập trực tiếp tới các thuộc tính/phương thức static đó

Còn với enum, thì hơi có vấn đề khi sử dụng như vậy. Vì việc tạo ra 1 enum từ 1 case của nó cũng chính là sử dụng tên Enum và . tới case đó

Nó cũng như là mình sử dụng tên Class/Struct truy cập vào thuộc tính/phương thức static vậy.

Với Swift 5.3 thì

  • Enum sẽ tự kết nối các case của nó với các thuộc tính/phương thức static của 1 Protocol mà nó implement
  • Yêu cầu là tụi nó phải trùng tên với nhau

Ví dụ cơ bản

/*
 - tên của các case khác tên của các thuộc tính/phương thức trong protocol
 */
protocol DecodingError {
  static var fileCorrupted: Self { get }
  static func keyNotFound(_ key: String) -> Self
}

enum JSONDecodingError: DecodingError {
  case _fileCorrupted
  case _keyNotFound(_ key: String)
  static var fileCorrupted: Self { return ._fileCorrupted }
  static func keyNotFound(_ key: String) -> Self { return ._keyNotFound(key) }
}

Ví dụ không cơ bản

  • Tất cả trùng nhau và sử dụng tương đồng với nhau

  • Như là:

    • Int.defaultValue

    • Array.defaultValue

    • Dictionary.defaultValue

  • Thì enum cũng là : Padding.defaultValue

protocol Defaultable {
    static var defaultValue: Self { get }
}

// make integers have a default value of 0
extension Int: Defaultable {
    static var defaultValue: Int { 0 }
}

// make arrays have a default of an empty array
extension Array: Defaultable {
    static var defaultValue: Array { [] }
}

// make dictionaries have a default of an empty dictionary
extension Dictionary: Defaultable {
    static var defaultValue: Dictionary { [:] }
}

enum Padding: Defaultable {
    case pixels(Int)
    case cm(Int)
    case defaultValue
}

let temp = Padding.defaultValue
print(temp)

8. Refine didSet Semantics

Mày không thoát được đâu con trai. Tu bi cơn ti niu!

Swift 5.3, cung cấp thêm cho bạn một cơ hội quay đầu khi đã lỡ tay gán giá trị mới cho 1 biến. Với property observers là didSet thì được cung cấp thêm 1 biến có tên là oldValue. Nó lưu trữ giá trị trước đó của biến. Giúp bạn truy xuất tới được giá trị trước và nếu bạn không dùng thì nó sẽ không được truy xuất ra.

Việc này có ý nghĩa với từng bài toán cụ thể mà bạn đang làm. Còn đây là 1 ví dụ cơ bản để minh hoạ cho cách dùng của nó.

class A1 {
    var firstArray = [1,2,3] {
        didSet { print("didSet called") }
    }

    var secondArray = [1,2,3,4] {
        didSet { print(oldValue) }
    }
}

let a1 = A1()
// This will not call the getter to fetch the oldValue of firstArray
a1.firstArray = [1,2]
// This will call the getter to fetch the oldValue of secondArray
a1.secondArray = [1]
print(a1.secondArray)

9. A new Float16 type

Thêm bạn thêm vui!

Thế giới chào đón thêm em Float16 vào gia đình nhà Float với Swift 5.3. Ngoài ra, còn liệt kê thêm các em Float khác cho bạn biết thêm.

let first: Float16 = 5
let second: Float32 = 11
let third: Float64 = 7
let fourth: Float80 = 13

Tham khảo

  • Swift Programming Language Evolution
  • What’s new in Swift 5.3? (Hacking With Swift)

 

OKAY! Mình xin tạm kết bài viết này ở đây. Nếu có thắc mắc hoặc góp ý gì, thì bạn có thể để lại comment hoặc contact tới mình. Cảm ơn bạn đã được bài viết này!

Thân ái và quyết thắng!

FacebookTweetPinYummlyLinkedInPrintEmailShares14

Related Posts:

  • feature_bg_swift_04
    Complete Concurrency với Swift 6
  • feature_bg_swift_04
    [Swift 6.2] Raw Identifiers - Đặt tên hàm có dấu…
  • feature_bg_swift_10
    Swift Optional trong 10 phút
  • KeyPath
    KeyPath trong 10 phút - Swift
Tags: Swift
Written by chuotfx

Hãy ngồi xuống, uống miếng bánh và ăn miếng trà. Chúng ta cùng nhau đàm đạo về đời, về code nhóe!

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Donate – Buy me a coffee!

Fan page

Fx Studio

Tags

Actor Advanced Swift AI api AppDistribution autolayout basic ios tutorial blog ci/cd closure collectionview combine concurrency crashlytics dart dart basic dart tour Declarative delegate deploy design pattern fabric fastlane firebase flavor flutter GCD gradients iOS MVVM optional Prompt engineering protocol Python rxswift safearea Swift Swift 5.5 SwiftData SwiftUI SwiftUI Notes tableview testing TravisCI unittest

Recent Posts

  • Thách thức đạo đức của Trí Tuệ Nhân Tạo (AI) và ý nghĩa thực tiễn
  • Role-playing vs. Persona-based Prompting
  • [Swift 6.2] Raw Identifiers – Đặt tên hàm có dấu cách, tại sao không?
  • Vibe Coding là gì?
  • Cách Đọc Sách Lập Trình Nhanh và Hiệu Quả Bằng GEN AI
  • Nỗ Lực – Hành Trình Kiến Tạo Ý Nghĩa Cuộc Sống
  • Ai Sẽ Là Người Fix Bug Khi AI Thống Trị Lập Trình?
  • Thời Đại Của “Dev Tay To” Đã Qua Chưa?
  • Prompt Engineering – Con Đường Để Trở Thành Một Nghề Nghiệp
  • Vấn đề Ảo Giác (hallucination) khi tương tác với Gen AI và cách khắc phục nó qua Prompt

You may also like:

  • [Swift 6.2] Raw Identifiers - Đặt tên hàm có dấu…
    feature_bg_swift_04
  • KeyPath trong 10 phút - Swift
    KeyPath
  • Lập trình hướng giao thức (POP) với Swift
    POP
  • Regular Expression (Regex) trong Swift
    feature_bg_swiftui_4
  • Complete Concurrency với Swift 6
    feature_bg_swift_04

Archives

  • June 2025 (1)
  • May 2025 (2)
  • April 2025 (1)
  • March 2025 (8)
  • January 2025 (7)
  • December 2024 (4)
  • September 2024 (1)
  • July 2024 (1)
  • June 2024 (1)
  • May 2024 (4)
  • April 2024 (2)
  • March 2024 (5)
  • January 2024 (4)
  • February 2023 (1)
  • January 2023 (2)
  • November 2022 (2)
  • October 2022 (1)
  • September 2022 (5)
  • August 2022 (6)
  • July 2022 (7)
  • June 2022 (8)
  • May 2022 (5)
  • April 2022 (1)
  • March 2022 (3)
  • February 2022 (5)
  • January 2022 (4)
  • December 2021 (6)
  • November 2021 (8)
  • October 2021 (8)
  • September 2021 (8)
  • August 2021 (8)
  • July 2021 (9)
  • June 2021 (8)
  • May 2021 (7)
  • April 2021 (11)
  • March 2021 (12)
  • February 2021 (3)
  • January 2021 (3)
  • December 2020 (3)
  • November 2020 (9)
  • October 2020 (7)
  • September 2020 (17)
  • August 2020 (1)
  • July 2020 (3)
  • June 2020 (1)
  • May 2020 (2)
  • April 2020 (3)
  • March 2020 (20)
  • February 2020 (5)
  • January 2020 (2)
  • December 2019 (12)
  • November 2019 (12)
  • October 2019 (19)
  • September 2019 (17)
  • August 2019 (10)

About me

Education, Mini Game, Digital Art & Life of coders
Contacts:
contacts@fxstudio.dev

Fx Studio

  • Home
  • About me
  • Contact us
  • Mail
  • Privacy Policy
  • Donate
  • Sitemap

Categories

  • Art (1)
  • Blog (45)
  • Code (11)
  • Combine (22)
  • Flutter & Dart (24)
  • iOS & Swift (102)
  • No Category (1)
  • RxSwift (37)
  • SwiftUI (80)
  • Tutorials (87)

Newsletter

Stay up to date with our latest news and posts.
Loading

    Copyright © 2025 Fx Studio - All rights reserved.