Swift6并发报错处理

Swift6并发报错处理

1、@MainActor

使用@MainActor相当于设置所有操作将在主线程。因此就没有并发问题了。

@MainActor
var id = UUID()

@MainActor
func test() async {
    id = UUID()
}

func test() {
    Task {
            await MainActor.run {// 在主线程操作

         }
    }
}

func test() {
    DispatchQueue.main.async {[weak self] in
        //在主线程操作
   }
}

2、@globalActor

创建自己的全局Actor,将所有对全局变量的读写限制在特定的Actor之中。

@globalActor
actor MyActor {
    static let shared = MyActor()
}

@MyActor
var id = UUID()

@MyActor
func test() async {
    id = UUID()
}

@MyActor
struct Model {
    static var id = UUID()
    
    func test() async {
        Self.id = UUID()
    }
}

3、mutex

在不使用actor增加异步代码时,可以使用mutex保护数据。

  • Mutex 是阻塞式的,适合用于快速、同步的状态访问;
  • 使用 Mutex 不会强制引入异步调用,因此不会干扰调用栈结构;
  • Mutex 本身符合 Sendable,可以很好地融入 Swift 6 的并发模型。
class Counter {
    private let mutex = Mutex(0)

    func increment() {
        mutex.withLock { count in
            count += 1
        }
    }

    func decrement() {
        mutex.withLock { count in
            count -= 1
        }
    }
}

4、nonisolated(unsafe)

直接告诉编译器这些代码不会引发数据竞争,有崩溃算我的,请忽略此问题。

nonisolated(unsafe)
var id = UUID()

func test() async {
    id = UUID()
}

5、@preconcurrency

@preconcurrency 主要用于暂时关闭 Swift 6 的严格并发检查。

1.比如引入的第三方库不支持Swift6:
@preconcurrency import UIKit
2.忽略某个方法的并发检查
@preconcurrency
func myOldFunction() {
    
}
3.忽略某个类的并发检查
@preconcurrency
class MyViewController: UIViewController {
    func goToNextScreen() {
        navigationController?.pushViewController(NextViewController(), animated: true)
    }
}

6、Sendable协议

主要用于并发编程,确保数据可以安全地在线程之间传递,避免数据竞争(Data Race)问题。以下类型隐式地自动遵守

  • 基础类型,Int、String、Bool 等;
  • 不含有引用类型成员的 struct;
  • 不含有引用类型关联值的 enum;
  • 所含元素类型符合 Sendable 协议的集合,如:Array、Dictionary 等。

class 需要主动声明遵守 Sendable 协议,并有以下限制:

  • class 必须是 final,否则有 Warning: Non-final class 'X' cannot conform to 'Sendable'; use ' @unchecked Sendable'

  • class 的存储属性必须是 immutable,否则有 Warning: Stored property 'x' of 'Sendable'-conforming class 'X' is mutable

  • class 的存储属性必须都遵守 Sendable 协议,否则 Warning: Stored property 'y' of 'Sendable'-conforming class 'X' has non-sendable type 'Y'

  • class 的祖先类 (如有) 必须遵守 Sendable 协议或者是 NSObject,否则 Error: 'Sendable' class 'X' cannot inherit from another class other than 'NSObject'。

或者使用 @unchecked Sendable 告诉编译器忽略检查

class User: @unchecked Sendable {
  var name: String
  var age: Int
}

7、@Sendable

@Sendable修饰的函数、闭包可以跨 actor 传递。

8、 MainActor.assumeIsolated

在 Swift 6,MainActor.assumeIsolated {} 允许你在 非 async 环境 下安全地访问 @MainActor 标记的变量,避免编译器报错,但不会进行线程检查(开发者需要确保代码真的在主线程运行)。

🌟 适用场景

  • 你在一个 同步(非 async)函数 里,想要访问 @MainActor 隔离的变量(比如 UIDevice.current.name)。
  • 你 知道代码已经在主线程运行,但编译器仍然报错 "Main actor-isolated property cannot be referenced from a nonisolated context"。
  • 你 不能让函数变成 async,比如在 Moya 这样的第三方库里。
/// 设备系统版本
@MainActor static var phoneSystemVersion: String {
    return UIDevice.current.systemVersion
}
    
let v = MainActor.assumeIsolated { WKAppDevice.phoneSystemVersion }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容