Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix crash when pressing create new account button ios 1019 #7483

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 3 additions & 9 deletions ios/MullvadVPN/Coordinators/ApplicationCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -450,14 +450,10 @@ final class ApplicationCoordinator: Coordinator, Presenting, @preconcurrency Roo
coordinator.preferredAccountNumberPublisher = preferredAccountNumberSubject.eraseToAnyPublisher()

coordinator.didFinish = { [weak self] _ in
MainActor.assumeIsolated {
self?.continueFlow(animated: true)
}
self?.continueFlow(animated: true)
}
coordinator.didCreateAccount = { [weak self] in
MainActor.assumeIsolated {
self?.appPreferences.isShownOnboarding = false
}
self?.appPreferences.isShownOnboarding = false
}

addChild(coordinator)
Expand Down Expand Up @@ -538,9 +534,7 @@ final class ApplicationCoordinator: Coordinator, Presenting, @preconcurrency Roo
)

coordinator.didFinish = { [weak self] _, reason in
MainActor.assumeIsolated {
self?.didDismissAccount(reason)
}
self?.didDismissAccount(reason)
}

coordinator.start(animated: animated)
Expand Down
4 changes: 2 additions & 2 deletions ios/MullvadVPN/Coordinators/LoginCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ final class LoginCoordinator: Coordinator, Presenting, @preconcurrency DeviceMan
nonisolated(unsafe) private var lastLoginAction: LoginAction?
private var subscriptions = Set<Combine.AnyCancellable>()

var didFinish: (@Sendable (LoginCoordinator) -> Void)?
var didCreateAccount: (@Sendable () -> Void)?
var didFinish: (@MainActor @Sendable (LoginCoordinator) -> Void)?
var didCreateAccount: (@MainActor @Sendable () -> Void)?

var preferredAccountNumberPublisher: AnyPublisher<String, Never>?
var presentationContext: UIViewController {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,8 @@ class AccountViewController: UIViewController, @unchecked Sendable {
let productState: ProductState = completion.value?.products.first
.map { .received($0) } ?? .failed

/// `@MainActor` isolation is safe here because
/// `ProductsRequestOperation` sets its `completionQueue` to `.main`
MainActor.assumeIsolated {
self?.setProductState(productState, animated: true)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ struct PaymentAlertPresenter {
func showAlertForError(
_ error: StorePaymentManagerError,
context: REST.CreateApplePaymentResponse.Context,
completion: (@Sendable () -> Void)? = nil
completion: (@MainActor @Sendable () -> Void)? = nil
) {
let presentation = AlertPresentation(
id: "payment-error-alert",
Expand Down Expand Up @@ -64,7 +64,7 @@ struct PaymentAlertPresenter {
func showAlertForResponse(
_ response: REST.CreateApplePaymentResponse,
context: REST.CreateApplePaymentResponse.Context,
completion: (@Sendable () -> Void)? = nil
completion: (@MainActor @Sendable () -> Void)? = nil
) {
guard case .noTimeAdded = response else {
completion?()
Expand Down
4 changes: 2 additions & 2 deletions ios/MullvadVPN/View controllers/Login/LoginInteractor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ final class LoginInteractor: @unchecked Sendable {
private let tunnelManager: TunnelManager
private let logger = Logger(label: "LoginInteractor")
private var tunnelObserver: TunnelObserver?
var didCreateAccount: (@Sendable () -> Void)?
var didCreateAccount: (@MainActor @Sendable () -> Void)?
var suggestPreferredAccountNumber: (@Sendable (String) -> Void)?

init(tunnelManager: TunnelManager) {
Expand All @@ -27,7 +27,7 @@ final class LoginInteractor: @unchecked Sendable {

func createAccount() async throws -> String {
let accountNumber = try await tunnelManager.setNewAccount().number
didCreateAccount?()
await didCreateAccount?()

return accountNumber
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,9 +221,7 @@ class OutOfTimeViewController: UIViewController, RootContainment {

default:
errorPresenter.showAlertForError(paymentFailure.error, context: .purchase) {
MainActor.assumeIsolated {
self.paymentState = .none
}
self.paymentState = .none
}
}
}
Expand Down Expand Up @@ -253,30 +251,23 @@ class OutOfTimeViewController: UIViewController, RootContainment {

paymentState = .restoringPurchases

/// Safe to assume `@MainActor` isolation because `SendStoreReceiptOperation` sets both its
/// `dispatchQueue` and `completionQueue` to `.main`
_ = interactor.restorePurchases(for: accountData.number) { [weak self] result in
guard let self else { return }

switch result {
case let .success(response):
Task { @MainActor in
MainActor.assumeIsolated {
switch result {
case let .success(response):
errorPresenter.showAlertForResponse(response, context: .restoration) {
MainActor.assumeIsolated {
self.paymentState = .none
}
self.paymentState = .none
}
}

case let .failure(error as StorePaymentManagerError):
Task { @MainActor in
case let .failure(error as StorePaymentManagerError):
errorPresenter.showAlertForError(error, context: .restoration) {
MainActor.assumeIsolated {
self.paymentState = .none
}
self.paymentState = .none
}
}

default:
Task { @MainActor in
default:
paymentState = .none
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ class RedeemVoucherViewController: UIViewController, UINavigationControllerDeleg
contentView.isEditing = false
interactor.redeemVoucher(code: code, completion: { [weak self] result in
guard let self else { return }
/// Safe to assume `@MainActor` isolation because
/// `TunnelManager.redeemVoucher` sets the `RedeemVoucherOperation`'s `completionQueue` to `.main`
MainActor.assumeIsolated {
switch result {
case let .success(value):
Expand Down
4 changes: 0 additions & 4 deletions ios/Operations/BackgroundObserver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,9 @@ public final class BackgroundObserver: OperationObserver {
}

public func didAttach(to operation: Operation) {
#if swift(>=6)
let expirationHandler = cancelUponExpiration
? { @MainActor in operation.cancel() } as? @MainActor @Sendable () -> Void
: nil
#else
let expirationHandler = cancelUponExpiration ? { operation.cancel() } : nil
#endif

taskIdentifier = backgroundTaskProvider.beginBackgroundTask(
withName: name,
Expand Down
5 changes: 2 additions & 3 deletions ios/Routing/Router/ApplicationRouter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -158,9 +158,8 @@ public final class ApplicationRouter<RouteType: AppRouteProtocol>: Sendable {
let context = RoutePresentationContext(route: route, isAnimated: animated, metadata: metadata)

delegate.applicationRouter(self, presentWithContext: context, animated: animated) { coordinator in
/*
Synchronize router when modal controllers are removed by swipe.
*/
/// Synchronize router when modal controllers are removed by swipe.
/// The delegate (`ApplicationCoordinator`) is `@MainActor` by virtue of being a `Coordinator`
MainActor.assumeIsolated {
if let presentable = coordinator as? Presentable {
presentable.onInteractiveDismissal { [weak self] coordinator in
Expand Down
Loading