Как получить объект 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 используется для общего доступа - в то время как контроллер представляет общий ресурс, есть кнопка "Копировать ссылку", доступная владельцу (и, возможно, пользователю, если вы разрешите публичный доступ). доступ - я не смотрел на это, поскольку мои вещи являются частными):