Lập trình iOS: Những cập nhật mới trong SWIFT 5.1

Lập trình iOS: Những cập nhật mới trong  SWIFT 5.1

1. Giới thiệu

    a) Ngày phát hành

  • Ngày 20 tháng 9 năm 2019, Apple cho ra mắt phiên bản Xcode 11 mới, và iOS 13. Và đi cùng với điều đó, Apple đã xuất bản phiên bản mới của ngôn ngữ phát triển của họ: Swift 5.1.

    b) Tổng quan

  • Swift 5.1 được xây dựng trên nền tảng của Swift 5.0, và được mở rộng tính ổn định của ngôn ngữ để biên dịch và sự ra mắt của module stability (mục 2). Với module stability, giờ đây chúng ta có thể tạo và chia sẻ các binary framework và việc này sẽ hỗ trợ cho các phiên bản sau này của Swift. Swift 5.1 còn mở rộng khả năng của ngôn ngữ và các thư viện chuẩn với các tính năng như property wrappers, result types, key path member lookup, diffing for appropriate collection types, và các API mới cho  Tất cả các tính năng mới trên của Swift 5.1 giúp cho việc thiết kế một API dễ dàng hơn và giảm số lượng code dư thừa.

2. Module stability

  1. Swift 5.1 cho phép việc tạo ra các Binary frameworks. Các framework này có thể được chia sẻ để tận dụng hỗ trợ cho module stability.
  2. Module stability được định nghĩa như 1 file module dựa trên văn bản, miêu tả các hàm (API) của các Binary framework và cho phép chúng được biên dịch với các trình biên dịch ở các phiên bản khác nhau.

3. Standard library update

Thư viện chuẩn của Swift 5.1 có 1 số tính năng mới sau đây:

  1. Hỗ trợ việc quản lý và thay đổi các diffs trên các bộ của các kiểu dữ liệu thích hợp.
  2. Tăng tính linh hoạt trong việc khởi tạo 1 mảng.
  3. Các API bổ sung cho thư viện giúp nó làm việc với String dễ dàng hơn, bao gồm việc tạo và quản lý các chuỗi kề nhau, các helpers trong việc làm việc với các chuỗi UNICODE, và các hàm khởi tạo và cho String.Index và Range.
  4. Nhiều sự cải tiến API để làm việc với kiểu phân loại SIMD, bao gồm việc mở rộng các vector, giảm vector, và thay đổi vị trí các phần tự trong vector.
  5. Các protocol có thể định danh để hỗ trợ các thực thể.

4. Các cải thiện về ngôn ngữ

    a) Sự cải thiện lớn trong việc tạo tự động các hàm khởi tạo memberwise

  1. Swift 5.1 giới thiệu một trong các sự cải thiện được xem là một trong các tính năng thường dùng nhất trong Swift: hàm khởi tạo memberwise  với các giá trị mặc định trong Struct.
  2. Trong các phiên bản trước của Swift (bao gồm Swift 5.0 và các phiên bản trước đó), chúng ta phải truyền tất các đối số cho hàm khởi tạo cho tất cả các thuộc tính trong Struct, kể cả khi các thuộc tính đó có giá trị mặc định hay không. Một hàm khởi tạo memberwise được tạo ra và yêu đầu đầy đủ đối số tương ứng với các  thuộc tính trong Struct, như ví dụ sau:
  3. Trong Swift 5.1, hàm khởi tạo memberwise sẽ sử dụng giá trị mặc định cho các thuộc tính chứa nó. Trong ví dụ trước, chúng ta cho thuộc tính score  giá trị 0, có nghĩa là chúng ta có thể truyền đối số để set nó trong hàm khởi tạo hoặc không.
  • Điều này quả thật rất tuyệt vời cho chúng ta trong việc tránh trùng lặp code. Bên cạnh đó nó còn mang lại cho chúng ta tính linh hoạt trong việc khởi tạo một Struct, đặc biệt khi bạn muốn tạo nhiều biến có cùng giá trị tiêu chuẩn. Nhưng bên cạnh những mặt tốt đó, nó không có tường minh khi mà nhiều hàm khởi tạo như vây mà chỉ cần khai báo một hàm:
  • Như ví dụ trên, chúng ta có một hàm cho việc khởi tạo, nhưng chúng ta có thể khai báo được hai kiểu. Và các kiểu khai báo không tường minh dường như không được xem như một public API – có nghĩa là khi bạn muốn viết một thư viện hay một framework, bạn cần phải khởi tạo đầy đủ tường minh.

    b) Implicit returns from single-expression functions

  • Swift 5.1 đã lượt bỏ một phần nhỏ nhưng vô cùng cần thiết trong ngôn ngữ: hàm single-expression trả về một giá trị và bây giờ đây nó có thể lược bỏ từ khoá return, Swift vẫn hiểu nó một cách không tường minh.
  • Ví dụ:
  • Swift 5:
  • Trong Swift 5.1, nếu một hàm chứa một single expression hay chứa một dòng lệnh để tính toán một giá trị, bạn có thể bỏ đi từ khoá return, như ví dụ sau:
  • Có thể mọi người thấy hơi hoang mang lúc đầu, nhưng tôi nghĩ mọi người sẽ sớm làm quen với nó.

    c) Opaque return types

  • Swift 5.1 đã đưa khái niệm về kiểu dữ liệu opaque vào Swift. Một kiểu opaque là kiểu khi mà chúng ta được biết về khả năng một đối tượng trong khi không hề biết về loại của đối tượng đó là gì.
  • Tổng thể cho thấy, nó như một protocol, nhưng kiểu trả về opaque khác hơn protocol rất là nhiều vì nó có thể làm việc với các kiểu associated, nó yêu cầu phải cùng loại. Chúng yêu cầu cùng loại được sử dụng trong nội bộ và chúng cho phép chúng ta giấu đi chi tiết thực thi.
  • Ví dụ, nếu muốn tạo ra các loại Animal khác nhau ta có thể viết như sau:
  • Nhưng có một vấn đề. Chuyện gì xảy ra nếu chúng ta thực hiện việc so sánh các biến đại diện của các lớp trên. Bạn có thể so sánh hai instance của Dog hay hay instance của Cat nhưng bạn không thể so sánh một instance Dog và Cat. Mặc dù hàm trả về kiểu Animal. Đôi khi nó không tường minh và khiến code khá rắc rối trong việc đọc hiểu. Vậy nên tôi có đề nghị nên viết như sau:

    d) Sử dụng Self để đại điện cho lớp chứa nó

  • Self  keyword trước đây đã cho phép chúng ta tự động refer một loại trong bối cảnh trong đó loại cụ thể thực tế không được biết đến. ví dụ: bằng cách refer đến implement type của protocol trong một protocol extension:
  • Phạm vi của Self giờ đã được mở rộng để bao gồm cả các loại cụ thể – như Enums, Structs và Class – cho phép chúng ta sử dụng Self như một loại bí danh đề cập đến một phương thức hoặc enclosing type, như thế này:
  • Thực tế là bây giờ chúng ta có thể sử dụng Self phía trên, thay vì tên loại TextTransform đầy đủ – Nó có thể giúp làm cho code của chúng ta gọn hơn một chút, đặc biệt là khi xử lý tên loại dài. Thậm chí chúng ta còn có thể sử dụng Self inline trong một phương thức hoặc thuộc tính:
  • Hãy xem ví dụ sau:

  • Trong ví dụ đầu tiên, tôi in một giá trị thuộc tính static poolConnections. Kể cả sau khi đã ghi đè giá trị, nó vẫn chỉ in ra giá trị của lớp cha. Và Self đến để giải quyết vấn đề này, như ở ví dụ trên. Nó giúp việc mở rộng các class trở nên dễ dàng hơn, góp phần củng cố kiến trúc phần mềm theo hướng mở rộng hơn.

    e) Warnings for ambiguous none cases

  • Các optional trong Swift  được implement như một Enum với hai trường hợp: somenone. Điều này đã dẫn đến khả năng nhầm lẫn nếu chúng ta tạo ra các Enum riêng không có trường hợp nào, sau đó bọc nó bên trong một optional.
  • Biến optionalColor mang giá trị `nil` bởi bị Swift cho .none có nghĩa là optional đang rỗng, hơn là 1 optional có giá trị là CustomColor.none.
  • Ở phiên bản Swift 5.1, sự nhầm lần này bây giờ đã in ra dòng warning: “Assuming you mean ‘Optional.none‘; did you mean ‘CustomColor.none‘ instead?” Điều này tránh sự phá vỡ khả năng tương thích nguồn của một lỗi, nhưng ít nhất thông báo cho các nhà phát triển rằng mã của họ có thể không hoàn toàn có nghĩa là những gì họ nghĩ.

    f) Matching optional enums against non-optionals

  • Khả năng advanced pattern matching của Swift cho phép chúng ta trực tiếp chuyển sang một giá trị optional – mà không cần phải unwrap trước – tuy nhiên, trước Swift 5.1, muốn làm như vậy yêu cầu chúng ta phải thêm dấu hỏi đánh dấu cho từng trường hợp match, như thế này:
  • Trong Swift 5.1, các dấu hỏi ở phía sau không còn cần thiết nữa và giờ đây chúng ta có thể chỉ cần refer trực tiếp từng trường hợp – giống như khi switch sang một giá trị non-optional:

    g) Ordered collection diffing

  • Swift 5.1 đưa đến cho chúng ta một phương thức mới difference(from:) giúp tính toán sự khác biệt giữa hai ordered collections – items cần xoá và items nào cần được loại bỏ. Nó có thể được sử dụng trên các ordered collection chứ các phần tử Equatable.
  • Để chứng minh điều này, chúng ta có thể tạo ra một mảng các score, tính toán sự khác biệt giữa điểm này với điểm khác, sau đó lặp lại những khác biệt đó và áp dụng từng điểm để làm cho collection của chúng ta giống nhau.
  • Có thể một trong số các bạn thấy nó quá dễ để đổi một collection thành một  collection khác – chỉ cần “gán bằng giá trị mới”. Nhưng điều đó lại dẫn đến hiệu xuất xấu trong việc cập nhật UI. Ví dụ tôi có một tableview T với datasource List. Datasource List được lấy từ web service. Khi data từ API thay đổi, List sẽ thay đổi và tableview T sẽ thay đổi theo. Và nếu như chúng ta chỉ gán mới mảng T bằng bộ dữ liệu mới từ Service, tableview sẽ được reload lại toàn bộ. Và việc cập nhật UI sẽ không mượt. Với API Diff bên trên, chúng ta có thể tính toán được các điểm khác biệt và thêm mới và xoá bớt các row trong tableview, điều này giúp giảm thời gian trong việc cập nhật UI.

5. Tổng kết

  • Swift 5.1 vẫn đang trong giai đoạn phát triển, và mặc dù việc phân nhánh cuối cùng cho chính Swift đã trôi qua nhưng vẫn có phạm vi để xem các thay đổi từ một số dự án liên quan khác.
  • Swift  bây giờ không chỉ ổn định về ABI, mà còn ổn định về module. Trên  hết, Swift 5.1 cũng bao gồm nhiều thay đổi và cải tiến nhỏ nhưng đáng hoan nghênh áp dụng cho hầu hết mọi code base.
  • Bên cạnh những mặt tốt,  như tính linh động trong code base, vẫn còn những tính năng cần phải lưu. Optional enums (mục 4.e, 4.f)  được xem như là bug, và nó nhắc nhở lập trình viên phải sử dụng kiểu tường minh để thay thế, để tránh việc dính lỗi trong tương lai.

Bạn có suy nghĩ gì? Bạn đã chuyển các dự án của bạn sang Swift 5.1 chưa? Nếu chưa, hãy thử nó ngay bây giờ!

 

Tài liệu tham khảo:

  1. https://swift.org/blog/swift-5-1-released/
  2. https://www.hackingwithswift.com/articles/182/whats-new-in-swift-5-1