Xcode 14 có gì mới? (Phần 3)

by DaoNM2
69 views

Swift 5.7

Các tính năng mới

  • Thư viện tiêu chuẩn có một Regex<Output> loại mới.Loại này đại diện cho một biểu thức chính quy mở rộng , cho phép các hoạt động xử lý chuỗi trôi chảy hơn. Bạn có thể tạo một Regex bằng cách khởi tạo từ một chuỗi :
let pattern = "a[bc]+" // matches "a" followed by one or more instances
                       // of either "b" or "c"
let regex = try! Regex(pattern)

Hoặc thông qua một regex literal:

let regex = #/a[bc]+/#

Có các thuật toán xử lý chuỗi mới hỗ trợ các loại StringRegex và arbitrary Collection. ( SE-0350 , 93923512 )

  • Xcode 14 kích hoạt cú pháp “dấu gạch chéo” của Swift 5.7 cho các ký tự biểu thức chính quy mới được giới thiệu. Trong một số trường hợp, kết quả là mã hiện có sử dụng /làm toán tử không được biên dịch. Bạn có thể định hướng điều này bằng cách thêm dấu ngoặc đơn (/). Bạn cũng có thể vô hiệu hóa hỗ trợ cho cú pháp chữ này bằng cách bỏ chọn “Bật các chữ viết Regex Bare Slash” (SWIFT_ENABLE_BARE_SLASH_REGEX = NO) trong project’s build settings. (93460568)
  • Các thao tác chuỗi trong phiên bản 5.7 của Thư viện tiêu chuẩn Swift triển khai xác thực cải tiến cho các chỉ mục chuỗi, khắc phục một số trường hợp biên trước đây dẫn đến lỗi thời gian chạy giả. Tuy nhiên, Swift hiện chẩn đoán các nỗ lực sử dụng chỉ mục ngoài giới hạn một cách đáng tin cậy hơn và điều này có thể làm lộ các lỗi lập chỉ mục chưa được phát hiện trước đó khi bạn biên dịch lại mã bằng Xcode 14. Nếu bạn thấy lỗi “Chỉ mục chuỗi nằm ngoài giới hạn” mới sau khi xây dựng lại, mã, sau đó kiểm tra kỹ xem bạn có đang áp dụng chỉ mục cũ cho giá trị chuỗi bị thay đổi không. Trong các bản phát hành trước, các trường hợp như vậy có thể âm thầm dẫn đến các giá trị bị hỏng hoặc vô nghĩa, trong khi ở Swift 5.7, giờ đây chúng gây ra lỗi thời gian chạy một cách đáng tin cậy. (89482809)
  • Giờ đây, Swift có thể suy ra loại trình giữ chỗ được viết ở nhiều vị trí cấp cao nhất. Loại suy luận hiện được đề xuất trong bản sửa lỗi.
// error: type placeholder may not appear in function return type
func replaceMe() -> _ { // note: replace the placeholder with the inferred type ‘Array<Int>’
  [ 42 ]
}
  • Xcode 13 đã cung cấp cài đặt bản dựng Swift có tên là “Tối ưu hóa thời gian tồn tại của đối tượng” không khả dụng trong Xcode 14. Nếu dự án của bạn đã tùy chỉnh cài đặt bản dựng này, thì giờ đây, nó sẽ trở thành cài đặt do người dùng xác định. Nó không có hiệu lực và bạn có thể loại bỏ nó. Xcode 14 hiện liên tục tối ưu hóa thời gian tồn tại của đối tượng. (91971848)
  • Xcode 14 giới thiệu một tính năng mới cho khả năng tương tác C: “SE-0324 Thư giãn chẩn đoán cho các đối số con trỏ đối với các hàm C.” Chẩn đoán thoải mái chỉ áp dụng cho các đối số kiểu con trỏ, không phải inout đối số. Giờ đây, chẩn đoán được nới lỏng đối với các inout đối số trong cùng điều kiện như đối số con trỏ. Ví dụ: chuyển đổi này từ một inout Int đối số sang loại tham số C const char * hiện được cho phép:
  // C declaration:
  // long read_long(const char *input);

  func test() -> Int {
    var x = 3
    return read_long(&x)
  }

Trước đây Swift đã chẩn đoán chuyển đổi inout-to-pointer là lỗi:

  error: cannot convert value of type 'UnsafePointer<Int>' to expected argument type
    'UnsafePointer<CChar>' (aka 'UnsafePointer<Int8>')
    return read_long(&x)
                     ^
  note: arguments to generic parameter 'Pointee' ('Int' and 'CChar' (aka 'Int8'))
  are expected to be equal
    return read_long(&x)
                     ^

Swift hiện hỗ trợ các tham chiếu đến optional các phương thức trên siêu dữ liệu giao thức, cũng như các tham chiếu được tra cứu động trên AnyObject siêu dữ liệu. Các tham chiếu này luôn có loại hàm chấp nhận một đối số và trả về một giá trị tùy chọn của loại hàm:

class Object {
  @objc func getTag() -> Int
}

@objc protocol P {
  @objc optional func didUpdateObject(withTag tag: Int)
}

let getTag: (AnyObject) -> (() -> Int)? = AnyObject.getTag

let didUpdateObject: (any P) -> ((Int) -> Void)? = P.didUpdateObject

Tải dữ liệu từ bộ nhớ thô được biểu thị bằng UnsafeRawPointer, UnsafeRawBufferPointer và các đối tác có thể thay đổi của chúng hiện hỗ trợ truy cập không được phân bổ. Điều này trước đây yêu cầu một cách giải quyết liên quan đến một bản sao trung gian:

let result = unalignedData.withUnsafeBytes { buffer -> UInt32 in
  var storage = UInt32.zero
  withUnsafeMutableBytes(of: &storage) {
    $0.copyBytes(from: buffer.prefix(MemoryLayout<UInt32>.size))
  }
  return storage
}

Hiện nay

let result = unalignedData.withUnsafeBytes { $0.loadUnaligned(as: UInt32.self) }

Ngoài ra, storeBytes(of:toByteOffset:as:) đã dỡ bỏ hạn chế căn chỉnh, do đó, giờ đây việc lưu trữ thành các phần bù tùy ý của bộ nhớ thô có thể thành công. ( SE-0349 , 93654008 )

UnsafeRawPointer và UnsafeMutableRawPointer có chức năng mới cho số học con trỏ, thêm các chức năng để lấy con trỏ nâng cao tới ranh giới căn chỉnh tiếp theo hoặc trước đó:

```swift
extension UnsafeRawPointer {
  public func alignedUp<T>(for: T.type) -> UnsafeRawPointer
  public func alignedDown<T>(for: T.type) -> UnsafeRawPointer
  public func alignedUp(toMultipleOf alignment: Int) -> UnsafeRawPointer
  public func alignedDown(toMultipleOf alignment: Int) -> UnsafeRawPointer
}
```
<!– /wp:code –> <!– wp:paragraph –> <p>Bây giờ bạn có thể sử dụng con trỏ tới <code>struct</code> để lấy con trỏ tới một trong các thuộc tính được lưu trữ của nó:</p> <!– /wp:paragraph –> <!– wp:code –> <pre class="wp-block-code"><code>“`swift withUnsafeMutablePointer(to: &myStruct) { let interiorPointer = $0.pointer(to: \.myProperty)! return myCFunction(interiorPointer) } “`

Swift đã đơn giản hóa việc so sánh giữa các con trỏ. Vì con trỏ là biểu diễn của các vị trí bộ nhớ trong một nhóm bộ nhớ cơ bản, nên giờ đây Swift cho phép so sánh con trỏ mà không yêu cầu chuyển đổi kiểu với các toán tử ==!=<<=>và >=. ( SE-0334 , 93667321 )

  • Giờ đây, bạn có thể sử dụng phương thức withMemoryRebound<T>() này trên bộ nhớ thô, bao gồm UnsafeRawPointer, UnsafeRawBufferPointer và các đối tượng có thể thay đổi của chúng. Ngoài ra, Swift đã làm rõ ngữ nghĩa withMemoryRebound<T>() khi được sử dụng trên bộ nhớ đã nhập (UnsafePointer<Pointee>, UnsafeBufferPointer<Pointee> và các đối tác có thể thay đổi của chúng). Trong khi Swift trước đây yêu cầu Pointee và T có cùng bước tiến, giờ đây bạn có thể liên kết Pointee và T lại trong các trường hợp là tổng hợp  hoặc ngược lại. Ví dụ: được cung cấp một UnsafeMutableBufferPointer<CGPoint>, bây giờ bạn có thể sử dụng withMemoryRebound để hoạt động tạm thời trên một UnsafeMutableBufferPointer<CGFloat>, bởi vì CGPoint là một tập hợp của CGFloat. ( SE- 0333 , 93668889 )
  • Giờ đây, bạn có thể gọi một hàm chung có giá trị là loại giao thức ở những nơi trước đây không thành công vì any các loại không tuân theo giao thức của chúng. Ví dụ:
protocol P {
  associatedtype A
  func getA() -> A
}

func takeP<T: P>(_ value: T) { }

func test(p: any P) {
  takeP(p) // was an error "type 'any P' cannot conform to 'P'", now accepted
}
  • Điều này hoạt động bằng cách mở giá trị của loại giao thức và chuyển loại cơ bản trực tiếp đến chức năng chung. ( SE-0352 , 93669112 )
  • Bây giờ, bạn có thể sử dụng một biểu thức giá trị mặc định với một loại tham số chung để làm mặc định đối số và loại của nó:
func compute<C: Collection>(_ values: C = [0, 1, 2]) {
  ...
}
  • Trình biên dịch hiện chấp nhận một cuộc gọi đến compute()và [Int] được suy ra C tại các trang web cuộc gọi không cung cấp đối số một cách rõ ràng. ( SE-0347 , 93669409 )
  • Giờ đây, bạn có thể sử dụng các giao thức với các loại và Self yêu cầu được liên kết dưới dạng các loại giá trị với từ khoá any. Bạn có thể gọi các phương thức giao thức trả về các loại được liên kết trên một kiểu any; kết quả là loại bị xóa đến giới hạn trên của loại được liên kết, là một kiểu any khác có cùng ràng buộc với loại được liên kết. Ví dụ:
protocol Surface {...}
  
protocol Solid {
  associatedtype SurfaceType: Surface
  func boundary() -> SurfaceType
}
  
let solid: any Solid = ...
  
// Type of 'boundary' is 'any Surface'
let boundary = solid.boundary()
  • Bạn không thể sử dụng các phương thức giao thức có loại được liên kết hoặc Self với any; tuy nhiên, cùng với SE-0352 , bạn có thể chuyển kiểu any cho một hàm có tham số chung bị ràng buộc với giao thức. Trong ngữ cảnh chung, các mối quan hệ kiểu là rõ ràng và bạn có thể sử dụng tất cả các phương thức giao thức. ( SE-0309 , 93928911)
  • Giờ đây, các giao thức có thể khai báo danh sách một hoặc nhiều loại được liên kết chính , cho phép viết các yêu cầu cùng loại trên các loại được liên kết đó bằng cách sử dụng cú pháp dấu ngoặc nhọn:
protocol Graph<Vertex, Edge> {
  associatedtype Vertex
  associatedtype Edge
}

Giờ đây, bạn có thể viết tên giao thức theo sau là các đối số loại trong dấu ngoặc nhọn, chẳng hạn như Graph<Int, String>, ở bất kỳ đâu mà yêu cầu tuân thủ giao thức có thể xuất hiện:

  func shortestPath<V, E>(_: some Graph<V, E>, from: V, to: V) -> [E]

  extension Graph<Int, String> {...}

  func build() -> some Graph<Int, String> {}

Tên giao thức theo sau bởi dấu ngoặc nhọn là cách viết tắt của yêu cầu tuân thủ, cùng với yêu cầu cùng loại đối với các loại liên kết chính của giao thức. Hai ví dụ đầu tiên ở trên tương đương như sau:

  func shortestPath<V, E, G>(_: G, from: V, to: V) -> [E]
    where G: Graph, G.Vertex == V, G.Edge == E

  extension Graph where Vertex == Int, Edge == String {...}
  • Hàm build()trả về some Graph<Int, String> không thể được viết bằng một mệnh đề where; đây là một ví dụ về loại kết quả không rõ ràng bị ràng buộc, đây là biểu thức mới trong Swift 5.7. ( SE-0346 , 93929372 )
  • Bạn có thể sử dụng các giao thức áp dụng các loại được liên kết chính với any để bật các loại tồn tại bị ràng buộc. Ví dụ:
let strings: any Collection<String> = [ "Hello" ]

Điều này làm cho việc viết các trình bao bọc xóa kiểu cho mã chung đơn giản hơn nhiều vì một loại trình bao bọc riêng biệt không còn cần thiết nữa:

protocol Producer<T> {
  associatedtype T
  func produce() -> T
}

typealias AnyProducer<T> = any Producer<T>

/*
struct AnyProducer<T> {
  var wrappedProduce: () -> T
}
*/

Giờ đây, bạn có thể sử dụng các giao thức với các loại được liên kết chính trong các loại tồn tại, cho phép các ràng buộc cùng loại đối với các loại được liên kết đó.

let strings: any Collection<String> = [ "Hello" ]
  • Lưu ý rằng các tính năng ngôn ngữ yêu cầu hỗ trợ thời gian chạy như diễn viên động ( isas?as!), cũng như cách sử dụng chung của các tồn tại được tham số hóa trong các loại chung (ví dụ: Array<any Collection<Int>>) liên quan đến việc kiểm tra tính khả dụng bổ sung để sử dụng. Giờ đây, bạn có thể triển khai lại các tập quán ở các vị trí chung với cấu trúc trình bao bọc xóa kiểu chung, giờ đây việc triển khai đơn giản hơn nhiều:
struct AnyCollection<T> {
  var wrapped: any Collection<T>
}

let arrayOfCollections: [AnyCollection<T>] = [ /**/ ]

Giờ đây, bạn có thể sử dụng các loại không rõ ràng trong tham số của hàm và chỉ số con khi chúng cung cấp cú pháp tốc ký để giới thiệu tham số chung. Ví dụ như sau:

func horizontal(_ v1: some View, _ v2: some View) -> some View {
  HStack {
    v1
    v2
  }
}

tương đương với:

func horizontal<V1: View, V2: View>(_ v1: V1, _ v2: V2) -> some View {
  HStack {
    v1
    v2
  }
}

Với điều này, some trong một loại tham số cung cấp một khái quát hóa trong đó người gọi chọn loại tham số cũng như giá trị của nó, trong khi some ở loại kết quả cung cấp một khái quát hóa trong đó người gọi chọn loại và giá trị kết quả. ( SE- 0341 , 93675336 )

Giờ đây, bạn có thể suy ra các loại tham số và kết quả từ phần thân của một bao đóng đa câu lệnh. Không còn sự phân biệt giữa các lần đóng đơn và đa câu lệnh.

Việc sử dụng các bao đóng trở nên ít cồng kềnh hơn bằng cách loại bỏ nhu cầu liên tục chỉ định các loại bao đóng rõ ràng, đôi khi có thể khá lớn (ví dụ: khi có nhiều tham số hoặc loại kết quả bộ dữ liệu phức tạp).

Ví dụ:

func map<T>(fn: (Int) -> T) -> T {
  return fn(42)
}

func computeResult<U: BinaryInteger>(_: U) -> U { /* processing */ }

let _ = map {
  if let $0 < 0 {
     // Do some processing.
  }

  return computeResult($0)
}
  • Giờ đây, bạn có thể suy ra loại kết quả map từ phần thân của dấu đóng được truyền dưới dạng đối số. ( SE-0326 , 93669647 )
  • Giờ đây, bạn có thể hủy bao bọc các biến tùy chọn bằng cú pháp tốc ký làm ẩn phần khai báo hiện có. Ví dụ như sau:
let foo: String? = "hello world"

if let foo {
  print(foo) // Prints "hello world”.
}

tương đương với:

let foo: String? = "hello world"

if let foo = foo {
  print(foo) // Prints "hello world”.
}
  • Giờ đây, bạn có thể làm cho các khai báo không khả dụng để sử dụng trong ngữ cảnh không đồng bộ với thuộc tính @available(*, noasync).
    Điều này bảo vệ người dùng API chống lại hành vi không xác định có thể xảy ra khi API sử dụng hoặc khuyến khích sử dụng lưu trữ cục bộ theo luồng trên các điểm tạm ngưng. Nó cũng bảo vệ các nhà phát triển chống lại việc giữ khóa trên các điểm treo, điều này có thể dẫn đến hành vi không xác định, đảo ngược mức độ ưu tiên hoặc deadlocks. ( SE-0340 , 93673989 )
  • Tập lệnh cấp cao nhất hiện hỗ trợ cuộc gọi không đồng bộ. Sử dụng một await bằng cách gọi một hàm không đồng bộ hoặc truy cập một biến bị cô lập sẽ chuyển cấp cao nhất sang ngữ cảnh không đồng bộ. Là một bối cảnh không đồng bộ, các biến cấp cao nhất được cách ly và cấp cao nhất được chạy trên .@[email protected] Lưu ý rằng quá trình chuyển đổi ảnh hưởng đến độ phân giải quá tải chức năng và bắt đầu một vòng lặp chạy ẩn để điều khiển máy móc đồng thời. Các tập lệnh chưa sửa đổi không bị ảnh hưởng bởi thay đổi này trừ khi -warn-concurrency được chuyển đến lời gọi trình biên dịch. Với -warn-concurrency, các biến ở cấp cao nhất được tách biệt với tác nhân chính và bối cảnh cấp cao nhất được tách biệt với tác nhân chính nhưng không phải là ngữ cảnh không đồng bộ. ( SE-0343 , 93674157 )
  • Swift hiện hỗ trợ lập trình phân tán với việc giới thiệu các tác nhân phân tán. Để biết thêm thông tin, hãy xem SE-0336 , SE-0344 . (70840120)
  • Bây giờ bạn có thể khai báo distributed actor và distributed func bên trong tệp distributed actor. Các tác nhân phân tán cung cấp các đảm bảo cách ly mạnh hơn so với các tác nhân “cục bộ” và chúng cho phép thực hiện các kiểm tra bổ sung đối với các loại trả về và tham số của các phương thức phân tán, ví dụ: kiểm tra xem chúng có tuân thủ Codable. Bạn có thể gọi các phương thức phân tán trên các tham chiếu “từ xa” của các tác nhân phân tán, biến các lệnh gọi đó thành các lệnh gọi thủ tục từ xa, bằng cách triển khai hệ thống tác nhân phân tán có thể cắm và mở rộng cho người dùng. Bản thân Swift không cung cấp bất kỳ hệ thống tác nhân phân tán cụ thể nào; tuy nhiên, các gói trong hệ sinh thái hoàn thành vai trò cung cấp các triển khai đó.
distributed actor Greeter { 
  var greetingsSent = 0
  
  distributed func greet(name: String) -> String {
    greetingsSent += 1
    return "Hello, \(name)!"
  }
}

func talkTo(greeter: Greeter) async throws {
  // The isolation of distributed actors is stronger. You can't refer to
  // any stored properties of distributed actors from outside of them.
  greeter.greetingsSent // You can't access the distributed actor-isolated property 'name' from a non-isolated context.
  
  // Remote calls are implicitly throwing and async, 
  // to account for the potential networking involved.
  let greeting = try await greeter.greet(name: "Alice")
  print(greeting) // Hello, Alice!
}

Trình khử khởi tạo, hầu hết các trình khởi tạo cho actor các loại và các loại bị hạn chế bởi một tác nhân toàn cầu như @MainActor các quy tắc đã sửa đổi về những biểu thức nào được phép trong phần thân của chúng. Là một phần của SE-327, mục tiêu của các bản sửa đổi này là cải thiện tính an toàn và biểu cảm của ngôn ngữ. Nhiều mẫu lập trình khác hiện được cho phép trong các bộ khởi tạo này.

Ví dụ: trình khởi tạo không đồng bộ của phiên bản actor trước Swift 5.7 đã đưa ra chẩn đoán bất kỳ lúc nào self thoát khỏi trình khởi tạo trước khi quay lại. Mục đích của chẩn đoán đó là để bảo vệ chống lại một cuộc chạy đua dữ liệu có thể xảy ra khi truy cập các thuộc tính được lưu trữ riêng biệt, nhưng nó đã được phát ra ngay cả khi không có quyền truy cập nguy hiểm.

Trong Swift 5.7, trình biên dịch hiện kiểm tra các trình khởi tạo này để tìm quyền truy cập nguy hiểm vào các thuộc tính được lưu trữ bị cô lập xảy ra sau khi thoát self:

actor Database {
  // ... other properties ...
  var rows: Int = 0

  init(_ world: DataUser) {
    defer { 
      print("last = \(self.rows)") // ❌ This access to 'rows' is illegal.
    }
    
    print("before = \(self.rows)") // ✅ This access to 'rows' is OK.
    world.publishDatabase(self)    // ✅ Passing 'self' is OK in Swift 5.7+.
    print("after = \(self.rows)")  // ❌ This access to 'rows' is illegal. 
    
    Task { [weak self] in          // ✅ Capturing 'self' is OK in Swift 5.7+.
      while let db = self { await db.prune() }
    }
  }
}

Đây là kiểm tra nhạy cảm với luồng điều khiển, nghĩa là truy cập bất hợp pháp không nhất thiết phải xuất hiện trên dòng nguồn sau khi thoát self(trong ví dụ trên, xem xét thời điểm defer thực thi). Trình biên dịch luôn chỉ ra một trong những lối thoát self khiến quyền truy cập trở thành bất hợp pháp.

Ngoài ra, các công cụ khởi tạo ủy quyền của một actor không còn luôn luôn không bị cô lập. Điều này có nghĩa là trình async khởi tạo ủy quyền có thể thực hiện những việc tương tự như trình khởi tạo không ủy quyền. (84476555)

  • Trình khởi tạo actor không còn yêu cầu viết từ khóa convenience để ủy quyền (SE-327). Trước Swift 5.7, việc thêm hoặc xóa convenience đối với public init của một diễn viên là một thay đổi không linh hoạt, đối với các thư viện được biên dịch có bật tiến hóa. Các thư viện được biên dịch cho Swift 5.7+ hiện có khả năng phục hồi trước những thay đổi trong quá trình triển khai các trình khởi tạo đó để ủy quyền hay không và các chương trình hiện có được biên dịch cho Swift 5.7+ sẽ không yêu cầu biên dịch lại. (87567878)
  • Các loại mới đại diện cho thời gian và đồng hồ hiện đã có sẵn. Điều này bao gồm một giao thức Clock để xác định đồng hồ, cho phép bạn xác định khái niệm về “hiện tại” và cách đánh thức sau một khoảng thời gian nhất định. Một giao thức InstantProtocol mới để xác định thời gian cũng có sẵn. Và một giao thức DurationProtocol mới để xác định khoảng thời gian đã trôi qua giữa hai loại InstantProtocol nhất định cũng có sẵn. Các loại để sử dụng chung là phổ biến nhất ClockSuspending và ClockContinuous, đại diện cho các đồng hồ cơ bản nhất cho hệ thống. Loại ClockSuspendingClock không tiến triển khi máy bị treo, ngược lại ContinuousClock tiến triển bất kể trạng thái của máy.
func delayedHello() async throws {
  try await Task.sleep(until: .now + .milliseconds(123), clock: .continuous)
  print("hello delayed world")
}

Clock cũng có các phương pháp để đo thời gian thực hiện công việc đã trôi qua. Trong trường hợp của SuspendingClock và ContinuousClock điều này đo lường với độ phân giải cao và phù hợp với điểm chuẩn.

let clock = ContinuousClock()
let elapsed = clock.measure {
  someLongRunningWork()
}

Trình biên dịch hiện phát ra cảnh báo khi một lớp không phải là lớp cuối cùng tuân theo một giao thức áp đặt yêu cầu cùng loại giữa Selfvà một loại được liên kết. Loại yêu cầu này làm cho sự phù hợp không hợp lý cho các lớp con.

Ví dụ: Swift 5.6 cho phép đoạn mã sau, trong thời gian chạy mã này sẽ xây dựng một phiên bản C và sub C không như mong đợi:

protocol P {
  associatedtype A : Q where Self == Self.A.B
}

protocol Q {
  associatedtype B

  static func getB() -> B
}

class C : P {
  typealias A = D
}

class D : Q {
  typealias B = C

  static func getB() -> C { return C() }
}

extension P {
  static func getAB() -> Self {
    // This is well-typed because `Self.A.getB()` returns
    // `Self.A.B`, which is equivalent to `Self`.
    return Self.A.getB()
  }
}

class SubC : C {}

// P.getAB() declares a return type of `Self`, so it should
// return `SubC`, but it actually returns a `C`.
print(SubC.getAB())
  • Để làm cho ví dụ trên đúng, class C cần phải trở thành final(trong trường hợp đó SubC không thể được khai báo) hoặc giao thức P cần được thiết kế lại để không bao gồm yêu cầu cùng loại Self == Self.A.B. (93675134)
  • Trình biên dịch hiện đưa ra chính xác các cảnh báo cho nhiều biểu thức hơn khi sử dụng tuân thủ giao thức và có thể không khả dụng khi chạy. Trước đây, các biểu thức tham chiếu thành viên và biểu thức xóa loại sử dụng các tuân thủ có khả năng không khả dụng chưa được chẩn đoán, dẫn đến các sự cố có thể xảy ra trong thời gian chạy.
struct Pancake {}
protocol Food {}

extension Food {
  var isGlutenFree: Bool { false }
}

@available(macOS 12.0, *)
extension Pancake: Food {}

@available(macOS 11.0, *)
func eatPancake(_ pancake: Pancake) {
  if (pancake.isGlutenFree) { // Warning: Conformance of 'Pancake' to 'Food' is only available in macOS 12.0 or newer.
    eatFood(pancake) // Warning: Conformance of 'Pancake' to 'Food' is only available in macOS 12.0 or newer.
  }
}

func eatFood(_ food: Food) {}

Các loại mờ (được biểu thị bằng some) hiện có thể được sử dụng ở các vị trí cấu trúc trong một loại kết quả, bao gồm cả việc có nhiều loại mờ trong cùng một kết quả. Ví dụ:

func getSomeDictionary() -> [some Hashable: some Codable] {
  return [ 1: "One", 2: "Two" ]
}

Các giao thức khác nhau trong thư viện chuẩn hiện khai báo các loại liên kết chính, ví dụ Sequencevà Collectionkhai báo một loại liên kết chính duy nhất Element. Ví dụ: điều này cho phép ghi lại các loại some Collection<Int>và any Collection<Int>. ( SE-0358 , 93929895 )

Vấn đề đã giải quyết

  • Các thuộc tính được lưu trữ trong Swift không được có thông tin loại có khả năng không khả dụng trong thời gian chạy. Tuy nhiên, trước Swift 5.7, trình biên dịch đã chấp nhận lỗi thuộc tính @available trên thuộc tính được lưu trữ khi thuộc tính có công cụ lazy sửa đổi hoặc trình bao bọc thuộc tính được đính kèm. Điều này có thể dẫn đến sự cố cho các ứng dụng chạy trên hệ điều hành cũ hơn. Trình biên dịch Swift hiện từ chối @available trên tất cả các thuộc tính được lưu trữ. (82713248) (FB9594187)
  • Phiên bản không đồng bộ addTeardownBlock của phương pháp trong XCTestCase hiện đã có. (85453819) (FB9762503)
  • Chẩn đoán về các biểu thức giá trị mặc định không tách biệt được giới thiệu cho Swift 5.6 trong bản phát hành Xcode 13.3 không còn nữa. Quy tắc được đề xuất trong SE-0327 không đủ chính xác để tránh gắn cờ một mẫu phổ biến nhưng vô thưởng vô phạt trong mã SwiftUI liên quan đến các thuộc tính @StateObject và @MainActor. (88971160)
  • Quá trình tái cấu trúc “Tạo Trình khởi tạo Memberwise” thêm chính xác các tham số cho các biến được đánh dấu bằng trình bao bọc thuộc tính. (89057767) (FB9910083)
  • Các thao tác chuỗi trong phiên bản 5.7 của Swift Standard Library triển khai xác thực cải tiến cho các chỉ mục chuỗi, khắc phục một số trường hợp biên trước đây dẫn đến lỗi thời gian chạy giả. Tuy nhiên, Swift hiện chẩn đoán các nỗ lực sử dụng chỉ mục ngoài giới hạn một cách đáng tin cậy hơn và điều này có thể làm lộ các lỗi lập chỉ mục chưa được phát hiện trước đó khi bạn biên dịch lại mã bằng Xcode 14. Nếu bạn thấy lỗi “Chỉ mục chuỗi nằm ngoài giới hạn” mới sau khi xây dựng lại, mã, sau đó kiểm tra kỹ xem bạn có đang áp dụng chỉ mục cũ cho giá trị chuỗi bị thay đổi không. Trong các bản phát hành trước, các trường hợp như vậy có thể âm thầm dẫn đến các giá trị bị hỏng hoặc vô nghĩa, trong khi ở Swift 5.7, giờ đây chúng gây ra lỗi thời gian chạy một cách đáng tin cậy. (89482809)
  • Khi xây dựng các thể hiện Chuỗi từ các chuỗi C, giờ đây Swift thực thi nghiêm ngặt việc chấm dứt null của bộ đệm đầu vào nếu bạn chuyển một đối số bằng cách chuyển đổi con trỏ. Hơn nữa, inout-to-pointer chuyển đổi hiện không được dùng cho cấu trúc Chuỗi. Các chức năng bị ảnh hưởng là String.init(cString:), String.init?(validatingUTF8:), String.decodeCString(_:as:repairingInvalidCodeUnits:) và String.init(decodingCString:as:). (90336023)
  • Chỉnh sửa tất cả trong Phạm vi đổi tên chính xác tất cả các lần xuất hiện của các biến được ghi lại bằng cách sử dụng cú pháp chụp tốc ký bao đóng [capturedVariable] hoặc cú pháp tốc ký if let optionalVariable. (91311033)
  • Bạn có thể sử dụng các giao thức áp dụng các loại được liên kết chính với từ khóa any để bật các loại tồn tại bị ràng buộc.Ví dụ:
let strings: any Collection<String> = [ "Hello" ]

Điều này làm cho việc viết các trình bao bọc xóa kiểu cho mã chung đơn giản hơn nhiều vì một loại trình bao bọc riêng biệt không còn cần thiết nữa:

protocol Producer<T> {
  associatedtype T
  func produce() -> T
}

typealias AnyProducer<T> = any Producer<T>

/*
struct AnyProducer<T> {
  var wrappedProduce: () -> T
}
*/

Trình biên dịch Swift không còn cảnh báo về các yêu cầu dư thừa trong các khai báo chung. Ví dụ: trong phiên bản beta 1, đoạn mã sau đã chẩn đoán một cảnh báo về T.Iterator : IteratorProtocol yêu cầu là dư thừa, bởi vì nó được ngụ ý bởi T : Sequence:

func firstElement<T: Sequence>(_: T) -> T.Element where T.Iterator: IteratorProtocol {...}

Một yêu cầu dư thừa không chỉ ra lỗi mã hóa và đôi khi nên đánh vần chúng cho mục đích tài liệu. Vì lý do này, những cảnh báo này hiện mặc định bị tắt.

Bạn có thể nhận hành vi trước đó và bật lại các cảnh báo này bằng cách đặt OTHER_SWIFT_FLAGS-X tùy chọn bản dựng trong Xcode thành “ frontend -warn-redundant-requirements”. (92092635)

  • Các phép chuyển động ( isas!as?) đến và từ các loại tồn tại được tham số hóa hiện kiểm tra chính xác các ràng buộc đối với các loại này. (92197049)
  • Đã sửa lỗi: Một số câu lệnh switch phức tạp nhất định trong phần đóng nhiều câu lệnh có thể khiến trình biên dịch gặp sự cố nếu chúng chứa câu lệnh fallthrough yêu cầu suy luận kiểu tại đích của nó, ví dụ: đích case sử dụng khớp mẫu với let các liên kết như case (let ..., let ...). (93796211)
  • Swift không thực hiện kiểm tra Có thể gửi khi thoát khỏi một actor để gọi vào mã không đồng bộ, không bị cô lập. Ví dụ:
func f(_: NS) async { }

actor A {
  func g(_ ns: NS) async {
    await f(ns) // Warn about passing non-Sendable type 'NS' to a non-isolated async function.
  }
}

Vấn đề đã biết

  • #if canImport(AudioVideoBridging)không biên dịch trên Mac Catalyst. (89289575)
    Giải pháp thay thế : Sử dụng #if os(macOS) để hạn chế AudioVideoBridging code cho các nền tảng được hỗ trợ.
  • ~= và các trường hợp trong switches thành công nếu toàn bộ chuỗi khớp, thay vì nếu có một kết quả khớp bên trong chuỗi. Điều này có thể thay đổi tùy thuộc vào kết quả của Swift Evolution cho SE-0357 . (93918632)
  • Trong Swift, một số kiểu chữ Foundation cho các loại chức năng (chẳng hạn như NSItemProvider.CompletionHandler) sẽ thấy @Sendable các loại chức năng, điều này có thể dẫn đến các cảnh báo không mong muốn trong mã chưa áp dụng Đồng thời Swift. Để loại bỏ các cảnh báo, hãy thay thế một tham chiếu đến bí danh kiểu chữ trong mã nguồn Swift bằng kiểu bên dưới của nó mà không có phần mở rộng @Sendable. (98343624)

    Ví dụ:
    thay thế: var completion: NSItemProvider.CompletionHandler
    bằng: var completion: (NSSecureCoding?, Error?) -> Void

Bài viết được dịch dựa trên nội dung release note xCode14 của Apple
Refer: https://developer.apple.com/documentation/xcode-release-notes/xcode-14-release-notes

Leave a Comment

* By using this form you agree with the storage and handling of your data by this website.