Как я могу обновить индикатор выполнения представления, используя AppSync S3ObjectManager? - PullRequest
0 голосов
/ 04 января 2019

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

1 Ответ

0 голосов
/ 08 января 2019

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

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

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

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

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

...