Options to init with @MainActor property as default value

huangapple go评论55阅读模式
英文:

Options to init with @MainActor property as default value

问题

I have translated the provided text:

我有一个类,直到现在在其初始化期间使用 UIApplication.shared 作为默认参数。它的简化版本如下:

final class MyClass {
    private var application: UIApplication
    
    init(application: UIApplication = UIApplication.shared) {
        self.application = application
    }
}

使用 Strict Concurrency Checking 选项时,现在会出现以下错误:

> 无法从非隔离上下文引用主要角色隔离的类属性 'shared'

这是因为 UIApplication 被标记为 @MainActor,因此其所有属性都是异步的:

@available(iOS 2.0, *)
@MainActor open class UIApplication : UIResponder {
open class var shared: UIApplication { get }

...
}

我看到两个解决方案:

#解决方案1

将属性标记为可选项,并在 init 期间初始化它。在某些情况下,这可能看起来是个好主意,但这样我们就失去了依赖注入属性并使其可测试的能力。此外,在我们知道属性确实已初始化的情况下,使用可选项会感到不便:

final class MyClass {
    private var application: UIApplication?
    
    @MainActor
    init() {
        self.application = UIApplication.shared
    }
}

#解决方案2

让调用者负责在 @MainActor 上初始化类:

final class MyClass {
    private var application: UIApplication
    
    init(application: UIApplication) {
        self.application = application
    }
    
    // 仅显示调用者将执行的内容
    @MainActor
    func option1ToInit() {
       _ = MyClass(application: UIApplication.shared)
    }
    
    // 仅显示调用者将执行的内容
    func option2ToInit() {
        Task {
            _ = await MyClass(application: UIApplication.shared)
        }
    }
}

第二种解决方案似乎效果不错,但我需要做一些重构工作,以便所有调用者都在 @MainActor 上执行。我想知道是否还有其他我忽略的选项。

英文:

I have a class which up until now used the UIApplication.shared as a default argument during it's initialisation. The simplified version of it:

final class MyClass {
    private var application: UIApplication
    
    init(application: UIApplication = UIApplication.shared) {
        self.application = application
    }
}

With Strict Concurrency Checking using the Complete option now gives the following error:

> Main actor-isolated class property 'shared' can not be referenced
> from a non-isolated context

It makes sense since UIApplication is marked as @MainActor hence, all it's properties are async:

@available(iOS 2.0, *)
@MainActor open class UIApplication : UIResponder {
open class var shared: UIApplication { get }

...
}

I see two solutions for this:

#Solution1

Mark the property as optional and initialise it during the init. In some cases it may seem as a good idea, but with this we loose the ability to dependency inject the property and make it testable. Also using optionals further when we know the property is indeed initialised is uncomfortable:

final class MyClass {
    private var application: UIApplication?
    
    @MainActor
    init() {
        self.application = UIApplication.shared
    }
}

#Solution2

Let's make the caller responsible for initialising the class on the @Mainactor:

final class MyClass {
    private var application: UIApplication
    
    init(application: UIApplication) {
        self.application = application
    }
    
    // Just to present what the caller would do
    @MainActor
    func option1ToInit() {
       _ = MyClass(application: UIApplication.shared)
    }
    
    // Just to present what the caller would do
    func option2ToInit() {
        Task {
            _ = await MyClass(application: UIApplication.shared)
        }
    }
}

The second solution seems to work nicely, however I need to do a bit of refactor work so all the callers are executing on the @MainActor. I was wondering if there is any other option I am missing here.

答案1

得分: 1

Sure, here's the translation of the code part:

如果您可以将@MainActor添加到init(根据您的描述似乎可以这样做),那么您只需要将.shared的访问移动到init中:

@MainActor
init(application: UIApplication? = nil) {
    self.application = application ?? .shared
}
英文:

If you can add @MainActor to init (which it seems you can from your description), then you just need to move the accessing of .shared into the init:

@MainActor
init(application: UIApplication? = nil) {
    self.application = application ?? .shared
}

huangapple
  • 本文由 发表于 2023年7月6日 20:27:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/76628839.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定