Как я могу обновить индикатор выполнения представления с помощью AppSync S3ObjectManager?

Я использую 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 в каждом контроллере и, возможно, использовать какой-то шаблон делегата?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
219
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вероятно, создание экземпляра нового клиента на каждом контроллере представления будет излишним. Установка и разборка требуют немного времени и системных ресурсов для выполнения, и вы, вероятно, предпочли бы в любом случае хранить эти действия отдельно от контроллера представления, просто для разделения ответственности.

На самом деле нет хорошего способа зарегистрировать прослушиватель для каждого объекта, поскольку мутации ставятся в очередь для возможной асинхронной доставки. Идея вашего делегата кажется лучшим подходом на данный момент.

ПРИМЕЧАНИЕ. Приведенный ниже код не протестирован и не ориентирован на многопотоковое исполнение.

Например, вы можете объявить одноэлементный делегат, который управляет наблюдателями для отдельных представлений, которым необходимо сообщать о ходе выполнения:

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, большое спасибо! У меня было смутное представление, но это дает мне отличный материал для работы, я обязательно опубликую суть того, над чем я работаю.

tgk 09.01.2019 17:29

Конечно, надеюсь, это окажется полезным.

Palpatim 09.01.2019 17:43

Другие вопросы по теме