Files
SideStore/AltStore/Operations/RefreshGroup.swift
Riley Testut 2d87c396f1 Deactivates apps by backing up + deleting them on iOS 13.5+
Deactivating apps by removing their profiles no longer works on iOS 13.5. Instead, AltStore will now back up the app by temporarily replacing it with AltBackup, then remove the app from the phone.
2020-05-17 23:47:26 -07:00

92 lines
2.4 KiB
Swift

//
// RefreshGroup.swift
// AltStore
//
// Created by Riley Testut on 6/20/19.
// Copyright © 2019 Riley Testut. All rights reserved.
//
import Foundation
import CoreData
import AltSign
class RefreshGroup: NSObject
{
let context: AuthenticatedOperationContext
let progress = Progress.discreteProgress(totalUnitCount: 0)
var completionHandler: (([String: Result<InstalledApp, Error>]) -> Void)?
var beginInstallationHandler: ((InstalledApp) -> Void)?
private(set) var results = [String: Result<InstalledApp, Error>]()
// Keep strong references to managed object contexts
// so they don't die out from under us.
private(set) var _contexts = Set<NSManagedObjectContext>()
private var isFinished = false
private let dispatchGroup = DispatchGroup()
private var operations: [Foundation.Operation] = []
init(context: AuthenticatedOperationContext = AuthenticatedOperationContext())
{
self.context = context
super.init()
}
/// Used to keep track of which operations belong to this group.
/// This does _not_ add them to any operation queue.
func add(_ operations: [Foundation.Operation])
{
for operation in operations
{
self.dispatchGroup.enter()
operation.completionBlock = { [weak self] in
self?.dispatchGroup.leave()
}
}
if self.operations.isEmpty && !operations.isEmpty
{
self.dispatchGroup.notify(queue: .global()) { [weak self] in
self?.finish()
}
}
self.operations.append(contentsOf: operations)
}
func set(_ result: Result<InstalledApp, Error>, forAppWithBundleIdentifier bundleIdentifier: String)
{
self.results[bundleIdentifier] = result
switch result
{
case .failure: break
case .success(let installedApp):
guard let context = installedApp.managedObjectContext else { break }
self._contexts.insert(context)
}
}
func cancel()
{
self.operations.forEach { $0.cancel() }
}
}
private extension RefreshGroup
{
func finish()
{
guard !self.isFinished else { return }
self.isFinished = true
self.completionHandler?(self.results)
}
}