Fixes RefreshAltStoreViewController never finishing

This commit is contained in:
Riley Testut
2020-03-30 15:23:20 -07:00
parent 45737250a7
commit 4e29c7a38c
4 changed files with 49 additions and 15 deletions

View File

@@ -52,12 +52,12 @@ private extension RefreshAltStoreViewController
switch result switch result
{ {
case .success: self.completionHandler?(.success(())) case .success: self.completionHandler?(.success(()))
case .failure(let error): case .failure(let error as NSError):
DispatchQueue.main.async { DispatchQueue.main.async {
sender.progress = nil sender.progress = nil
sender.isIndicatingActivity = false sender.isIndicatingActivity = false
let alertController = UIAlertController(title: NSLocalizedString("Failed to Refresh AltStore", comment: ""), message: error.localizedDescription, preferredStyle: .alert) let alertController = UIAlertController(title: NSLocalizedString("Failed to Refresh AltStore", comment: ""), message: error.localizedFailureReason ?? error.localizedDescription, preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: NSLocalizedString("Try Again", comment: ""), style: .default, handler: { (action) in alertController.addAction(UIAlertAction(title: NSLocalizedString("Try Again", comment: ""), style: .default, handler: { (action) in
refresh() refresh()
})) }))

View File

@@ -135,7 +135,7 @@ extension AppManager
} }
} }
self.run([findServerOperation]) self.run([findServerOperation], context: context)
return findServerOperation return findServerOperation
} }
@@ -162,7 +162,7 @@ extension AppManager
} }
authenticationOperation.addDependency(findServerOperation) authenticationOperation.addDependency(findServerOperation)
self.run([authenticationOperation]) self.run([authenticationOperation], context: context)
return authenticationOperation return authenticationOperation
} }
@@ -184,7 +184,7 @@ extension AppManager
} }
} }
self.run([fetchSourceOperation]) self.run([fetchSourceOperation], context: nil)
} }
func fetchSources(completionHandler: @escaping (Result<Set<Source>, Error>) -> Void) func fetchSources(completionHandler: @escaping (Result<Set<Source>, Error>) -> Void)
@@ -231,7 +231,7 @@ extension AppManager
NotificationCenter.default.post(name: AppManager.didFetchSourceNotification, object: self) NotificationCenter.default.post(name: AppManager.didFetchSourceNotification, object: self)
} }
self.run(operations) self.run(operations, context: nil)
} }
} }
@@ -244,7 +244,7 @@ extension AppManager
let fetchAppIDsOperation = FetchAppIDsOperation(context: authenticationOperation.context) let fetchAppIDsOperation = FetchAppIDsOperation(context: authenticationOperation.context)
fetchAppIDsOperation.resultHandler = completionHandler fetchAppIDsOperation.resultHandler = completionHandler
fetchAppIDsOperation.addDependency(authenticationOperation) fetchAppIDsOperation.addDependency(authenticationOperation)
self.run([fetchAppIDsOperation]) self.run([fetchAppIDsOperation], context: authenticationOperation.context)
} }
@discardableResult @discardableResult
@@ -311,7 +311,7 @@ extension AppManager
} }
deactivateAppOperation.addDependency(findServerOperation) deactivateAppOperation.addDependency(findServerOperation)
self.run([deactivateAppOperation], requiresSerialQueue: true) self.run([deactivateAppOperation], context: context, requiresSerialQueue: true)
} }
func installationProgress(for app: AppProtocol) -> Progress? func installationProgress(for app: AppProtocol) -> Progress?
@@ -434,7 +434,7 @@ private extension AppManager
} }
} }
awaitAuthenticationOperation.addDependency(authenticationOperation) awaitAuthenticationOperation.addDependency(authenticationOperation)
self.run([awaitAuthenticationOperation], requiresSerialQueue: true) self.run([awaitAuthenticationOperation], context: group.context, requiresSerialQueue: true)
} }
else else
{ {
@@ -541,7 +541,7 @@ private extension AppManager
let operations = [downloadOperation, refreshAnisetteDataOperation, fetchProvisioningProfilesOperation, resignAppOperation, sendAppOperation, installOperation] let operations = [downloadOperation, refreshAnisetteDataOperation, fetchProvisioningProfilesOperation, resignAppOperation, sendAppOperation, installOperation]
group.add(operations) group.add(operations)
self.run(operations) self.run(operations, context: group.context)
return progress return progress
} }
@@ -590,7 +590,7 @@ private extension AppManager
let operations = [fetchProvisioningProfilesOperation, refreshAppOperation] let operations = [fetchProvisioningProfilesOperation, refreshAppOperation]
group.add(operations) group.add(operations)
self.run(operations) self.run(operations, context: group.context)
return progress return progress
} }
@@ -665,7 +665,7 @@ private extension AppManager
UNUserNotificationCenter.current().add(request) UNUserNotificationCenter.current().add(request)
} }
func run(_ operations: [Foundation.Operation], requiresSerialQueue: Bool = false) func run(_ operations: [Foundation.Operation], context: OperationContext?, requiresSerialQueue: Bool = false)
{ {
for operation in operations for operation in operations
{ {
@@ -673,9 +673,9 @@ private extension AppManager
{ {
case _ where requiresSerialQueue: fallthrough case _ where requiresSerialQueue: fallthrough
case is InstallAppOperation, is RefreshAppOperation: case is InstallAppOperation, is RefreshAppOperation:
if let previousOperation = self.serialOperationQueue.operations.last if let context = context, let previousOperation = self.serialOperationQueue.operations.last(where: { context.operations.contains($0) })
{ {
// Ensure operations execute in the order they're added, since they may become ready at different points. // Ensure operations execute in the order they're added (in same context), since they may become ready at different points.
operation.addDependency(previousOperation) operation.addDependency(previousOperation)
} }
@@ -684,6 +684,8 @@ private extension AppManager
default: default:
self.operationQueue.addOperation(operation) self.operationQueue.addOperation(operation)
} }
context?.operations.add(operation)
} }
} }

View File

@@ -655,8 +655,11 @@ private extension AuthenticationOperation
completionHandler(false) completionHandler(false)
#else #else
DispatchQueue.main.async { DispatchQueue.main.async {
let context = AuthenticatedOperationContext(context: self.context)
context.operations.removeAllObjects() // Prevent deadlock due to endless waiting on previous operations to finish.
let refreshViewController = self.storyboard.instantiateViewController(withIdentifier: "refreshAltStoreViewController") as! RefreshAltStoreViewController let refreshViewController = self.storyboard.instantiateViewController(withIdentifier: "refreshAltStoreViewController") as! RefreshAltStoreViewController
refreshViewController.context = self.context refreshViewController.context = context
refreshViewController.completionHandler = { _ in refreshViewController.completionHandler = { _ in
completionHandler(true) completionHandler(true)
} }

View File

@@ -16,6 +16,25 @@ class OperationContext
{ {
var server: Server? var server: Server?
var error: Error? var error: Error?
let operations: NSHashTable<Foundation.Operation>
init(server: Server? = nil, error: Error? = nil, operations: [Foundation.Operation] = [])
{
self.server = server
self.error = error
self.operations = NSHashTable<Foundation.Operation>.weakObjects()
for operation in operations
{
self.operations.add(operation)
}
}
convenience init(context: OperationContext)
{
self.init(server: context.server, error: context.error, operations: context.operations.allObjects)
}
} }
class AuthenticatedOperationContext: OperationContext class AuthenticatedOperationContext: OperationContext
@@ -26,6 +45,16 @@ class AuthenticatedOperationContext: OperationContext
var certificate: ALTCertificate? var certificate: ALTCertificate?
weak var authenticationOperation: AuthenticationOperation? weak var authenticationOperation: AuthenticationOperation?
convenience init(context: AuthenticatedOperationContext)
{
self.init(server: context.server, error: context.error, operations: context.operations.allObjects)
self.session = context.session
self.team = context.team
self.certificate = context.certificate
self.authenticationOperation = context.authenticationOperation
}
} }
@dynamicMemberLookup @dynamicMemberLookup