Как получить объект CKShare уже существующего ресурса (чтобы получить URL ресурса)

Я пытаюсь разрешить пользователям моего приложения получить ссылку на общий доступ iCloud к записи, которой они уже поделились. Я могу получить URL при создании общего ресурса с помощью let share = CKShare(rootRecord: CKRecord) следуют Apple UISharingController, Однако каждый раз, когда я использую этот метод, старая ссылка становится недействительной и удаляет других из общего ресурса, к которому они уже присоединились. Как я могу позволить пользователям (владельцам записей) получать общий URL-адрес для записей CKShare объект в любое время?

//Initially shares the record
let share = CKShare(rootRecord: newRecord)
share[CKShare.SystemFieldKey.title] = "Group" as CKRecordValue?        
let modifyRecordsOperation = CKModifyRecordsOperation( recordsToSave: [newRecord, share], recordIDsToDelete: nil)

//Activates the UISharingController (code not shown)

2 ответа

Предполагая, что запись уже была опубликована, вы можете получить URL-адрес для приглашения дополнительных участников со следующим:

      if let shareReference = record.share {
    database.fetch(withRecordID: shareReference.recordID) { (share, error) in
        let shareURL = (share as? CKShare)?.url
    }
}

Если вы хотели показать UICloudSharingControllerснова для существующего общего ресурса (без создания нового URL-адреса) вы можете сделать:

      let sharingController = UICloudSharingController { (_, prepareCompletionHandler) in

    func createNewShare() {
        let operationQueue = OperationQueue()
        operationQueue.maxConcurrentOperationCount = 1

        let share = CKShare(rootRecord: record)
        share[CKShare.SystemFieldKey.title] = "Title" as CKRecordValue
        share.publicPermission = .readWrite

        let modifyRecordsOp = CKModifyRecordsOperation(recordsToSave: [share, record], recordIDsToDelete: nil)
        modifyRecordsOp.modifyRecordsCompletionBlock = { records, recordIDs, error in
            prepareCompletionHandler(share, self, error)
        }
        modifyRecordsOp.database = database
        operationQueue.addOperation(modifyRecordsOp)
    }

    if let shareReference = record.share {
        database.fetch(withRecordID: shareReference.recordID) { (share, error) in
            guard let share = share as? CKShare else {
                createNewShare()
                return
            }
            prepareCompletionHandler(share, self, nil)
        }
    } else {
        createNewShare()
    }
}

Похоже, у вас здесь много проблем. Я бы рекомендовал внимательно изучить документацию UICloudSharingController.

Первая проблема заключается в том, что в предоставленном вами коде вы создаете новый общий ресурс каждый раз, когда вам нужно создать его один раз, а затем показать этот общий ресурс в любое время, когда вы захотите с ним взаимодействовать (включая получение общего ресурса). URL). После того, как вы создадите свой общий ресурс, вы, вероятно, захотите как-то сохранить его на устройстве (это может быть так же просто, как сохранить его в UserDefaults).

Вторая проблема заключается в том, что создается впечатление, что вы неправильно создаете UICloudSharingController. Когда вы изначально создаете CKShare, вы должны использовать инициализатор UICloudSharingController init ( prepareHandler :) и создать общий ресурс внутри этого.

Согласно документации для различных инициализаторов (выделено мое):

Важный

Вы должны инициализировать контроллер с правильным методом инициализатора. Не используйте init(prepareHandler:), если CKRecord уже используется совместно. Аналогично, не используйте init(share:container:), если CKRecord не является общим. Использование неправильного инициализатора приводит к ошибкам при сохранении записи.

И затем, когда вы захотите показать shareSheet, вы используете инициализатор UICloudSharingController (инициализатор share: container:) и отправляете ему общий ресурс, который вы сохранили на устройстве.

Вот код, предоставленный в документации UICloudSharingController для создания CKShare:

func presentCloudSharingController(_ sender: Any) {  guard
    let barButtonItem = sender as? UIBarButtonItem,
    let rootRecord = self.recordToShare else {
    return
  }

  let cloudSharingController = UICloudSharingController { [weak self] (controller, completion: @escaping (CKShare?, CKContainer?, Error?) -> Void) in
    guard let `self` = self else {
      return
    }
    self.share(rootRecord: rootRecord, completion: completion)
  }

  if let popover = cloudSharingController.popoverPresentationController {
    popover.barButtonItem = barButtonItem
  }
  self.present(cloudSharingController, animated: true) {}
}

func share(rootRecord: CKRecord, completion: @escaping (CKShare?, CKContainer?, Error?) -> Void) {
  let shareRecord = CKShare(rootRecord: rootRecord)
  let recordsToSave = [rootRecord, shareRecord];
  let container = CKContainer.default()
  let privateDatabase = container.privateCloudDatabase
  let operation = CKModifyRecordsOperation(recordsToSave: recordsToSave, recordIDsToDelete: []) 
  operation.perRecordCompletionBlock = { (record, error) in
    if let error = error {
      print("CloudKit error: \(error.localizedDescription)")
    }
  }

  operation.modifyRecordsCompletionBlock = { (savedRecords, deletedRecordIDs, error) in
    if let error = error {
      completion(nil, nil, error)
    } else {
      completion(shareRecord, container, nil)
    }
  }

  privateDatabase.add(operation)
}

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

 let share = // yourCKShare
 let container = // yourCKContainer
 let viewController = // yourViewController
 let shareController = UICloudSharingController(share: share, container: container)
 viewController.present(shareController, animated: true)

И, наконец, чтобы ответить на часть URL вашего вопроса, UICloudSharingController используется для общего доступа - в то время как контроллер представляет общий ресурс, есть кнопка "Копировать ссылку", доступная владельцу (и, возможно, пользователю, если вы разрешите публичный доступ). доступ - я не смотрел на это, поскольку мои вещи являются частными):

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