Tôi Thích Rất Nhiều Diễn Viên Khác Nhau

Cảnh báo này chỉ ra một nguy cơ tiềm ẩn thực sự về các cuộc đua dữ liệu và nó không nằm trong phạm vi “phân tích trình biên dịch có thể chứng minh mã này an toàn hơn”. Tôi nghĩ rằng có những cách mà trình biên dịch có thể loại bỏ hạn chế với một số hạn chế khác, ví dụ: chúng ta có thể làm cho nó có thể thêm cách ly vào một lớp con của một siêu lớp không Sendable, không bị cô lập, nhưng lớp con không thể được tạo Sendable và các ghi đè vẫn phải là nonisolated. Những người khác đã đưa ra ý tưởng bằng cách nào đó làm cho các lớp con bị cô lập tự động làm cho mọi thứ từ siêu lớp bị cô lập với tác nhân chính, nhưng điều đó sẽ đi kèm với những hạn chế khác như không thể nâng cấp và không có quyền truy cập vào các phương thức nonisolated async, điều này sẽ không giải quyết được vấn đề ở đây với phương thức fulfillment.

Lý do tại sao điều này không an toàn là vì XCTestCase không phải là Sendable vì nó là một kiểu tham chiếu với trạng thái có thể thay đổi. Đối với các kiểu không Sendable, bạn có một đảm bảo rằng chỉ một miền cách ly có quyền truy cập vào giá trị tại bất kỳ thời điểm nào. XCTestCase.fulfillment là một phương thức nonisolated async, có nghĩa là nó được đánh giá ngoài tác nhân chính, vì vậy việc gọi nó từ tác nhân chính sẽ chuyển self qua một ranh giới cách ly. Trong khi trường hợp kiểm tra của bạn bị tạm ngưng chờ kết quả của fulfillment, công việc khác có thể xảy ra trên tác nhân chính để truy cập self, ví dụ: nếu bạn đã thực hiện bất kỳ công việc đồng thời nào trong phương thức kiểm tra của mình. Theo hiểu biết của tôi, XCTest sẽ tạo các phiên bản mới của loại trường hợp kiểm tra của bạn cho các kiểm tra song song, vì vậy tôi nghĩ thời điểm duy nhất bạn có thể có quyền truy cập đồng thời vào self là nếu bạn đã tự thực hiện bất kỳ công việc đồng thời nào trong các kiểm tra của mình.

Nếu thử nghiệm của bạn không thực sự thực hiện bất kỳ điều gì đồng thời, bạn có thể sử dụng nonisolated(unsafe) để ngăn chặn cảnh báo:


@MainActor func testSomething() async { let something = expectation(description: "something") // This is okay because this test isn't doing any concurrent work, and any tests // that run in parallel will have a completely separate instance of the test case type. nonisolated(unsafe) let `self` = self await self.fulfillment(of: [something]) }

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

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