gpt4 book ai didi

ios - SwiftUI 和 UICloudSharingController 互相讨厌

转载 作者:行者123 更新时间:2023-11-29 11:25:13 24 4
gpt4 key购买 nike

我有一个使用 SwiftUI 的项目需要 CloudKit 共享,但我无法让 UICloudSharingController 在 SwiftUI 环境中正常运行。

第一个问题

使用 UIViewControllerRepresentable 直接包装 UICloudSharingController 会产生一个无限旋转器(参见 this )。正如对其他系统 Controller (如 UIActivityViewController)所做的那样,我将 UICloudSharingController 包装在一个包含 UIViewController 中,如下所示:

struct CloudSharingController: UIViewControllerRepresentable {
@EnvironmentObject var store: CloudStore
@Binding var isShowing: Bool

func makeUIViewController(context: Context) -> CloudControllerHost {
let host = CloudControllerHost()
host.rootRecord = store.noteRecord
host.container = store.container
return host
}

func updateUIViewController(_ host: CloudControllerHost, context: Context) {
if isShowing, host.isPresented == false {
host.share()
}
}
}


final class CloudControllerHost: UIViewController {
var rootRecord: CKRecord? = nil
var container: CKContainer = .default()
var isPresented = false

func share() {
let sharingController = shareController
isPresented = true
present(sharingController, animated: true, completion: nil)
}

lazy var shareController: UICloudSharingController = {
let controller = UICloudSharingController { [weak self] controller, completion in
guard let self = self else { return completion(nil, nil, CloudError.controllerInvalidated) }
guard let record = self.rootRecord else { return completion(nil, nil, CloudError.missingNoteRecord) }

let share = CKShare(rootRecord: record)
let operation = CKModifyRecordsOperation(recordsToSave: [record, share], recordIDsToDelete: [])
operation.modifyRecordsCompletionBlock = { saved, _, error in
if let error = error {
return completion(nil, nil, error)
}
completion(share, self.container, nil)
}
self.container.privateCloudDatabase.add(operation)
}
controller.delegate = self
controller.popoverPresentationController?.sourceView = self.view
return controller
}()
}

这允许 Controller 正常启动,但是......

第二个问题

点击关闭按钮或滑动以关闭, Controller 将消失,但没有通知它已被关闭。启动呈现 Controller 的 SwiftUI View 的 @State 属性仍然是 true。没有明显的方法来检测模态的解除。经过一些试验,我发现呈现 Controller 是在 SceneDelegate 中创建的原始 UIHostingController。通过一些 hackery,您可以将 UIHostingController 子类中引用的对象注入(inject)到 CloudSharingController 中。这将使您检测到解雇并将 @State 属性设置为 false。然而,所有导航栏按钮在关闭后都不再起作用,所以你只能点击一次这个东西。场景的其余部分完全可用,但导航栏中的按钮没有响应。

第三个问题

即使您可以让 UICloudSharingController 正常显示和关闭,点击任何共享方法(消息、邮件等)都会使 Controller 消失,没有动画和用于共享的 Controller URL 没有出现。没有崩溃或控制台消息——它就消失了。

演示

我在 GitHub 上做了一个快速而肮脏的项目来演示这个问题:CloudKitSharing .它只是创建一个 String 和一个 CKRecord 来使用 CloudKit 来表示它。该界面显示 String(一个 UUID)和一个用于共享它的导航栏按钮:

CloudKitSharingUI

请求

有什么方法可以在 SwiftUI 中使用 UICloudSharingController 吗?没有时间在 UIKit 或自定义共享 Controller 中重建项目(我知道——处于最前沿的代价 💩)

最佳答案

我得到了这个工作 - 最初,我将 UICloudSharingController 包装在 UIViewControllerRepresentable 中,很像你提供的链接(我在构建它时引用了它),并且简单将它添加到 SwiftUI .sheet() View 。这在 iPhone 上有效,但在 iPad 上失败了,因为它需要你设置 popoverPresentationController?.sourceView,而我没有,因为我用 SwiftUI 按钮触发了工作表.

回到绘图板,我将按钮本身重新构建为 UIViewRepresentable,并且能够使用 SeungUn Ham 在这里建议的 rootViewController 技巧来呈现 View 。在 iPhone 和 iPad 上一切正常——至少在模拟器中是这样。

我的按钮:

struct UIKitCloudKitSharingButton: UIViewRepresentable {
typealias UIViewType = UIButton

@ObservedObject
var toShare: ObjectToShare
@State
var share: CKShare?

func makeUIView(context: UIViewRepresentableContext<UIKitCloudKitSharingButton>) -> UIButton {
let button = UIButton()

button.setImage(UIImage(systemName: "person.crop.circle.badge.plus"), for: .normal)
button.addTarget(context.coordinator, action: #selector(context.coordinator.pressed(_:)), for: .touchUpInside)

context.coordinator.button = button
return button
}

func updateUIView(_ uiView: UIButton, context: UIViewRepresentableContext<UIKitCloudKitSharingButton>) {

}

func makeCoordinator() -> Coordinator {
Coordinator(self)
}

class Coordinator: NSObject, UICloudSharingControllerDelegate {
var button: UIButton?

func cloudSharingController(_ csc: UICloudSharingController, failedToSaveShareWithError error: Error) {
//Handle some errors here.
}

func itemTitle(for csc: UICloudSharingController) -> String? {
return parent.toShare.name
}

var parent: UIKitCloudKitSharingButton

init(_ parent: UIKitCloudKitSharingButton) {
self.parent = parent
}

@objc func pressed(_ sender: UIButton) {
//Pre-Create the CKShare record here, and assign to parent.share...

let sharingController = UICloudSharingController(share: share, container: myContainer)

sharingController.delegate = self
sharingController.availablePermissions = [.allowReadWrite]
if let button = self.button {
sharingController.popoverPresentationController?.sourceView = button
}

UIApplication.shared.windows.first?.rootViewController?.present(sharingController, animated: true)
}
}
}

关于ios - SwiftUI 和 UICloudSharingController 互相讨厌,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59230784/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com