Skip to content

Commit abefbd4

Browse files
committed
Merge branch 'fix-crash-when-pressing-create-new-account-button-ios-1019'
2 parents 7cc4ba8 + adc7130 commit abefbd4

9 files changed

+25
-41
lines changed

ios/MullvadVPN/Coordinators/ApplicationCoordinator.swift

+3-9
Original file line numberDiff line numberDiff line change
@@ -450,14 +450,10 @@ final class ApplicationCoordinator: Coordinator, Presenting, @preconcurrency Roo
450450
coordinator.preferredAccountNumberPublisher = preferredAccountNumberSubject.eraseToAnyPublisher()
451451

452452
coordinator.didFinish = { [weak self] _ in
453-
MainActor.assumeIsolated {
454-
self?.continueFlow(animated: true)
455-
}
453+
self?.continueFlow(animated: true)
456454
}
457455
coordinator.didCreateAccount = { [weak self] in
458-
MainActor.assumeIsolated {
459-
self?.appPreferences.isShownOnboarding = false
460-
}
456+
self?.appPreferences.isShownOnboarding = false
461457
}
462458

463459
addChild(coordinator)
@@ -538,9 +534,7 @@ final class ApplicationCoordinator: Coordinator, Presenting, @preconcurrency Roo
538534
)
539535

540536
coordinator.didFinish = { [weak self] _, reason in
541-
MainActor.assumeIsolated {
542-
self?.didDismissAccount(reason)
543-
}
537+
self?.didDismissAccount(reason)
544538
}
545539

546540
coordinator.start(animated: animated)

ios/MullvadVPN/Coordinators/LoginCoordinator.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ final class LoginCoordinator: Coordinator, Presenting, @preconcurrency DeviceMan
2121
nonisolated(unsafe) private var lastLoginAction: LoginAction?
2222
private var subscriptions = Set<Combine.AnyCancellable>()
2323

24-
var didFinish: (@Sendable (LoginCoordinator) -> Void)?
25-
var didCreateAccount: (@Sendable () -> Void)?
24+
var didFinish: (@MainActor @Sendable (LoginCoordinator) -> Void)?
25+
var didCreateAccount: (@MainActor @Sendable () -> Void)?
2626

2727
var preferredAccountNumberPublisher: AnyPublisher<String, Never>?
2828
var presentationContext: UIViewController {

ios/MullvadVPN/View controllers/Account/AccountViewController.swift

+2
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,8 @@ class AccountViewController: UIViewController, @unchecked Sendable {
161161
let productState: ProductState = completion.value?.products.first
162162
.map { .received($0) } ?? .failed
163163

164+
/// `@MainActor` isolation is safe here because
165+
/// `ProductsRequestOperation` sets its `completionQueue` to `.main`
164166
MainActor.assumeIsolated {
165167
self?.setProductState(productState, animated: true)
166168
}

ios/MullvadVPN/View controllers/Account/PaymentAlertPresenter.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ struct PaymentAlertPresenter {
1616
func showAlertForError(
1717
_ error: StorePaymentManagerError,
1818
context: REST.CreateApplePaymentResponse.Context,
19-
completion: (@Sendable () -> Void)? = nil
19+
completion: (@MainActor @Sendable () -> Void)? = nil
2020
) {
2121
let presentation = AlertPresentation(
2222
id: "payment-error-alert",
@@ -64,7 +64,7 @@ struct PaymentAlertPresenter {
6464
func showAlertForResponse(
6565
_ response: REST.CreateApplePaymentResponse,
6666
context: REST.CreateApplePaymentResponse.Context,
67-
completion: (@Sendable () -> Void)? = nil
67+
completion: (@MainActor @Sendable () -> Void)? = nil
6868
) {
6969
guard case .noTimeAdded = response else {
7070
completion?()

ios/MullvadVPN/View controllers/Login/LoginInteractor.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ final class LoginInteractor: @unchecked Sendable {
1414
private let tunnelManager: TunnelManager
1515
private let logger = Logger(label: "LoginInteractor")
1616
private var tunnelObserver: TunnelObserver?
17-
var didCreateAccount: (@Sendable () -> Void)?
17+
var didCreateAccount: (@MainActor @Sendable () -> Void)?
1818
var suggestPreferredAccountNumber: (@Sendable (String) -> Void)?
1919

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

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

3232
return accountNumber
3333
}

ios/MullvadVPN/View controllers/OutOfTime/OutOfTimeViewController.swift

+10-19
Original file line numberDiff line numberDiff line change
@@ -221,9 +221,7 @@ class OutOfTimeViewController: UIViewController, RootContainment {
221221

222222
default:
223223
errorPresenter.showAlertForError(paymentFailure.error, context: .purchase) {
224-
MainActor.assumeIsolated {
225-
self.paymentState = .none
226-
}
224+
self.paymentState = .none
227225
}
228226
}
229227
}
@@ -253,30 +251,23 @@ class OutOfTimeViewController: UIViewController, RootContainment {
253251

254252
paymentState = .restoringPurchases
255253

254+
/// Safe to assume `@MainActor` isolation because `SendStoreReceiptOperation` sets both its
255+
/// `dispatchQueue` and `completionQueue` to `.main`
256256
_ = interactor.restorePurchases(for: accountData.number) { [weak self] result in
257257
guard let self else { return }
258-
259-
switch result {
260-
case let .success(response):
261-
Task { @MainActor in
258+
MainActor.assumeIsolated {
259+
switch result {
260+
case let .success(response):
262261
errorPresenter.showAlertForResponse(response, context: .restoration) {
263-
MainActor.assumeIsolated {
264-
self.paymentState = .none
265-
}
262+
self.paymentState = .none
266263
}
267-
}
268264

269-
case let .failure(error as StorePaymentManagerError):
270-
Task { @MainActor in
265+
case let .failure(error as StorePaymentManagerError):
271266
errorPresenter.showAlertForError(error, context: .restoration) {
272-
MainActor.assumeIsolated {
273-
self.paymentState = .none
274-
}
267+
self.paymentState = .none
275268
}
276-
}
277269

278-
default:
279-
Task { @MainActor in
270+
default:
280271
paymentState = .none
281272
}
282273
}

ios/MullvadVPN/View controllers/RedeemVoucher/RedeemVoucherViewController.swift

+2
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,8 @@ class RedeemVoucherViewController: UIViewController, UINavigationControllerDeleg
116116
contentView.isEditing = false
117117
interactor.redeemVoucher(code: code, completion: { [weak self] result in
118118
guard let self else { return }
119+
/// Safe to assume `@MainActor` isolation because
120+
/// `TunnelManager.redeemVoucher` sets the `RedeemVoucherOperation`'s `completionQueue` to `.main`
119121
MainActor.assumeIsolated {
120122
switch result {
121123
case let .success(value):

ios/Operations/BackgroundObserver.swift

-4
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,9 @@ public final class BackgroundObserver: OperationObserver {
2626
}
2727

2828
public func didAttach(to operation: Operation) {
29-
#if swift(>=6)
3029
let expirationHandler = cancelUponExpiration
3130
? { @MainActor in operation.cancel() } as? @MainActor @Sendable () -> Void
3231
: nil
33-
#else
34-
let expirationHandler = cancelUponExpiration ? { operation.cancel() } : nil
35-
#endif
3632

3733
taskIdentifier = backgroundTaskProvider.beginBackgroundTask(
3834
withName: name,

ios/Routing/Router/ApplicationRouter.swift

+2-3
Original file line numberDiff line numberDiff line change
@@ -158,9 +158,8 @@ public final class ApplicationRouter<RouteType: AppRouteProtocol>: Sendable {
158158
let context = RoutePresentationContext(route: route, isAnimated: animated, metadata: metadata)
159159

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

0 commit comments

Comments
 (0)