Я использую AWSAppSyncClient для загрузки файлов, но мне не удается связать хук прогресса загрузки с представлением.
AWSAppSyncClient - это свойство делегата приложения, инициализированного с помощью S3ObjectManager. Метод диспетчера объектов upload имеет доступ к процессу загрузки через AWSTransferUtilityUplaodExpression:
expression.progressBlock = {(task, progress) in
DispatchQueue.main.async(execute: {
// Can we update the controller's progress bar here?
print("Progress: \(Float(progress.fractionCompleted))")
})
}
Мой контроллер вызывает загрузку, вызывая perform:
var appSyncClient: AWSAppSyncClient? // retrieved from the app delegate singleton
appSyncClient?.perform(mutation: CreatePostMutation(input: input)) { (result, error) in ...
С чем я борюсь: как мне предоставить S3ObjectManager ссылку на контроллер? Я думал создать экземпляр AWSAppSyncClient в каждом контроллере и, возможно, использовать какой-то шаблон делегата?





Вероятно, создание экземпляра нового клиента на каждом контроллере представления будет излишним. Установка и разборка требуют немного времени и системных ресурсов для выполнения, и вы, вероятно, предпочли бы в любом случае хранить эти действия отдельно от контроллера представления, просто для разделения ответственности.
На самом деле нет хорошего способа зарегистрировать прослушиватель для каждого объекта, поскольку мутации ставятся в очередь для возможной асинхронной доставки. Идея вашего делегата кажется лучшим подходом на данный момент.
ПРИМЕЧАНИЕ. Приведенный ниже код не протестирован и не ориентирован на многопотоковое исполнение.
Например, вы можете объявить одноэлементный делегат, который управляет наблюдателями для отдельных представлений, которым необходимо сообщать о ходе выполнения:
class AppSyncS3ObjectManagerProgressWatcher {
typealias ProgressSubscription = UUID
static let shared = AppSyncS3ObjectManagerProgressWatcher()
private var watchers = [UUID: AppSyncS3ObjectManagerProgressDelegate?]()
func add(_ watcher: AppSyncS3ObjectManagerProgressDelegate) -> ProgressSubscription {
let subscription = UUID()
weak var weakWatcher = watcher
watchers[subscription] = weakWatcher
return subscription
}
func remove(_ subscription: ProgressSubscription?) {
guard let subscription = subscription else {
return
}
watchers[subscription] = nil
}
}
extension AppSyncS3ObjectManagerProgressWatcher: AppSyncS3ObjectManagerProgressDelegate {
func progressReportingExpression(forDownloadingObject object: AWSS3ObjectProtocol) -> AWSS3TransferUtilityDownloadExpression {
let expression = AWSS3TransferUtilityDownloadExpression()
expression.progressBlock = { _, progress in
self.didReportProgress(forDownloadingObject: object, progress: progress)
}
return expression
}
func progressReportingExpression(forUploadingObject object: AWSS3ObjectProtocol & AWSS3InputObjectProtocol) -> AWSS3TransferUtilityUploadExpression {
let expression = AWSS3TransferUtilityUploadExpression()
expression.progressBlock = { _, progress in
self.didReportProgress(forUploadingObject: object, progress: progress)
}
return expression
}
func didReportProgress(forDownloadingObject object: AWSS3ObjectProtocol, progress: Progress) {
for watcher in watchers.values {
watcher?.didReportProgress(forDownloadingObject: object, progress: progress)
}
}
func didReportProgress(forUploadingObject object: AWSS3ObjectProtocol & AWSS3InputObjectProtocol, progress: Progress) {
for watcher in watchers.values {
watcher?.didReportProgress(forUploadingObject: object, progress: progress)
}
}
}
Везде, где вы согласовываете S3TransferUtility с S3ObjectManager, вы должны сделать что-то вроде:
extension AWSS3TransferUtility: AWSS3ObjectManager {
public func download(s3Object: AWSS3ObjectProtocol, toURL: URL, completion: @escaping ((Bool, Error?) -> Void)) {
let completionBlock: AWSS3TransferUtilityDownloadCompletionHandlerBlock = { task, url, data, error -> Void in
if let _ = error {
completion(false, error)
} else {
completion(true, nil)
}
}
let progressReportingExpression = AppSyncS3ObjectManagerProgressWatcher
.shared
.progressReportingExpression(forDownloadingObject: s3Object)
let _ = self.download(
to: toURL,
bucket: s3Object.getBucketName(),
key: s3Object.getKeyName(),
expression: progressReportingExpression,
completionHandler: completionBlock)
}
public func upload(s3Object: AWSS3ObjectProtocol & AWSS3InputObjectProtocol, completion: @escaping ((_ success: Bool, _ error: Error?) -> Void)) {
let completionBlock : AWSS3TransferUtilityUploadCompletionHandlerBlock = { task, error -> Void in
if let _ = error {
completion(false, error)
} else {
completion(true, nil)
}
}
let progressReportingExpression = AppSyncS3ObjectManagerProgressWatcher
.shared
.progressReportingExpression(forUploadingObject: s3Object)
let _ = self.uploadFile(
s3Object.getLocalSourceFileURL()!,
bucket: s3Object.getBucketName(),
key: s3Object.getKeyName(),
contentType: s3Object.getMimeType(),
expression: progressReportingExpression,
completionHandler: completionBlock
).continueWith { (task) -> Any? in
if let err = task.error {
completion(false, err)
}
return nil
}
}
}
А затем в представлении отчета о ходе выполнения:
override func awakeFromNib() {
super.awakeFromNib()
progressSubscription = AppSyncS3ObjectManagerProgressWatcher.shared.add(self)
}
func didReportProgress(forUploadingObject object: AWSS3InputObjectProtocol & AWSS3ObjectProtocol, progress: Progress) {
// TODO: Filter by object local URI/key/etc to ensure we're updating the correct progress
print("Progress received for \(object.getKeyName()): \(progress.fractionCompleted)")
self.progress = progress
}
Как я уже отмечал, этот код не тестировался, но он должен описать общий подход, с которого вы можете начать. Буду признателен за ваши отзывы и хотел бы услышать, какой подход вы в конечном итоге выберете.
Наконец, не стесняйтесь открывать запрос функции на нашей странице проблем: https://github.com/awslabs/aws-mobile-appsync-sdk-ios/issues
Конечно, надеюсь, это окажется полезным.
вау, я благодарен, что вы нашли время напечатать это @Palpatim, большое спасибо! У меня было смутное представление, но это дает мне отличный материал для работы, я обязательно опубликую суть того, над чем я работаю.