我正在研究 Apple 的CloudKit Catalog 示例,我只是想让身份验证正常工作。我想在浏览器窗口(而不是 Node JS)中运行此 JS 代码。我从他们的网站上获取了他们的代码,如下所示:
\n\n<!DOCTYPE html>\n<html lang="en">\n <head></head>\n <body>\n <script>\n window.addEventListener(\'cloudkitloaded\', function() {\n\n CloudKit.configure({\n containers: [{\n containerIdentifier: \'iCloud.com.example.CloudKitCatalog\',\n apiToken: \'b86f0b5db29f04f45badba0366f39b7130a505f07765b5ba3a2ceb0cb3d96c0c\',\n persist: true,\n environment: \'production\',\n signInButton: { id: \'sign-in-button\', theme: \'black\' },\n signOutButton: { id: \'sign-out-button\', theme: \'black\' }\n }]\n })\n\n var container = CloudKit.getDefaultContainer()\n\n //-----\n function gotoAuthenticatedState(userIdentity) {\n var name = userIdentity.nameComponents\n if(name) {\n displayUserName(name.givenName + \' \' + name.familyName)\n } else {\n displayUserName(\'User record name: \' + userIdentity.userRecordName)\n }\n container\n .whenUserSignsOut()\n …Run Code Online (Sandbox Code Playgroud) 我有两个应用程序访问 iCloud。第一个是基于文档的应用程序,通过 UIDocument/NSDocument 类使用 iCloud 文件夹,无需 CloudKit。相反,第二个应用程序使用 CloudKit 通过 cloudkit 数据库而不是 iCloud 文件夹访问数据。
当我禁用 iCloud 驱动器时,第一个应用程序会从列表中消失,但第二个应用程序仍然存在,这表明对 iCloud 的访问仍然可用。
但是,当 iCloud 驱动器被禁用时,CKContainer.accountStatus 返回“noAccount”,即使我已登录。当我忽略它并运行查询时,它不会返回任何记录。
iCloud 驱动器占用大量设备存储空间,因此一些用户可能会选择禁用它。出于这个原因,我更喜欢访问 iCloud,而不是使用 iCloud 驱动器。有办法吗?
顺便说一句,iCloud 文档对 CloudKit 和 iCloud Drive 进行了强烈区分,这可能被解释为 iCloud 驱动器的存在对于 iCloud 数据库访问并不重要的另一个证据。
我的应用程序是用 SwiftUI 编写的,使用 Cloudkit 来存储核心数据中的记录。我能够获取用于@FetchRequest填充列表的记录。现在我想获取当前用户的 iCloud ID 并将其与另一个全局 ID 进行比较,但我遇到了问题fetchUserRecordID...
查看 Cloudkit Dashboard 的记录类型时,我可以看到用户记录Users。但每次运行下面的代码时,我都会收到以下错误:“无法从容器“iCloud.com.my_container_name”的服务器获取容器配置”
我正在运行 Xcode 12.2 Beta 4
ContentView.swift
struct ContentView: View {
@Environment(\.managedObjectContext) private var viewContext
init() {
isCreator()
}
var body: some View {
Text("Hello World")
}
func isCreator() {
CKContainer.default().fetchUserRecordID(completionHandler: { (recordId, error) in
guard let record = recordId, error == nil else {
print("Error: \(error!.localizedDescription)")
return
}
print("Found record")
// Now do something with record...
})
}
} // …Run Code Online (Sandbox Code Playgroud) 大多数 CloudKit+CoreData 教程都使用 SwiftUI,其实现包括 @FetchRequest,它会自动检测 CoreData 获取中的更改并刷新 UI。
https://www.hackingwithswift.com/quick-start/swiftui/what-is-the-fetchrequest-property-wrapper
如果没有 SwiftUI,我该如何实现这一目标?我希望能够控制刷新 UI 的方式,以响应检测到因 iCloud 更新而发生的 CoreData 更改。
我用它来设置 NSPersistentCloudKitContainer 并注册远程通知:
let storeDescription = NSPersistentStoreDescription()
storeDescription.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
let container = NSPersistentCloudKitContainer(name: "CoreDataDemo")
container.persistentStoreDescriptions = [storeDescription]
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
container.viewContext.automaticallyMergesChangesFromParent = true
container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
NotificationCenter.default.addObserver(self, selector: #selector(didReceiveCloudUpdate), name: .NSPersistentStoreRemoteChange, object: container.persistentStoreCoordinator)
Run Code Online (Sandbox Code Playgroud)
但是我不知道如何以 SwiftUI 实现自动处理的方式处理 .NSPercientStoreRemoteChange 。该方法被许多不同的线程非常频繁地调用(仅在启动时就多次调用)。
我在尝试初始化 Cloudkit架构时收到此错误:
Error Domain=NSCocoaErrorDomain Code=134060 "A Core Data error occurred." UserInfo={NSLocalizedFailureReason=Couldn't initialize CloudKit schema because no stores in the coordinator are configured to use CloudKit: ()}
Run Code Online (Sandbox Code Playgroud)
这是我的代码:
private lazy var persistentContainer: NSPersistentContainer = {
let container = NSPersistentCloudKitContainer(name: self.objectModelName)
// Create a store description for a CloudKit-backed local store
let cloudStoreLocation = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!.appendingPathComponent("iCloud.sqlite")
let cloudStoreDescription = NSPersistentStoreDescription(url: cloudStoreLocation)
cloudStoreDescription.configuration = "iCloud"
// Set the container options on the cloud store
cloudStoreDescription.cloudKitContainerOptions = NSPersistentCloudKitContainerOptions(containerIdentifier: "iCloud.myname.app")
// Update …Run Code Online (Sandbox Code Playgroud) 我正在使用 NSPersistentCloudKitContainer 通过 CloudKit 和 CoreData 在用户之间同步和共享一些记录。在根据我的需要从Apple 网站调整示例代码后,工作得相对良好。
然而,NSPersistentCloudKitContainer 有一个名为initializeCloudKitSchema 的方法来初始化和验证CloudKit 架构。使用它的最佳实践是什么,因为它似乎没有有用的作用(Apple 示例文档和代码中没有使用它,并且无论如何创建方案时都没有它)?
当应用程序冷启动时, @Environment(. undoManager ) 为零,并保持为零,直到用户更改视图。当视图更改时,undoManager 将被设置并且撤消功能可用。
在下面的 gif 中,您可以看到在用户切换到新视图“焦点”然后再返回之前,撤消操作是不可用的。
以下是设置 undoManager 环境的 SwiftUI 代码:
@Environment(\.managedObjectContext) private var viewContext
@Environment(\.undoManager) private var undoManager
Run Code Online (Sandbox Code Playgroud)
[...]
listOfCards.task{
viewContext.undoManager = undoManager //nil when starting from cold start
}
Run Code Online (Sandbox Code Playgroud)
@main App 实例化一个 NSPersistentCloudKitContainer 并将其设置为 ManagedObjectContext
mainView
.environment(\.managedObjectContext, persistenceController.container.viewContext)
Run Code Online (Sandbox Code Playgroud)
到目前为止,我已经尝试过以下一些方法来解决此问题:
A) 在每个视图中添加以下内容...
.onChange(of: undoManager) { _ in
print(undoManager)
viewContext.undoManager = undoManager}
Run Code Online (Sandbox Code Playgroud)
检测何时设置 undoManager 并将其链接到 viewContext。运气不好,没有接到电话。
B)还尝试添加观察者:
private let undoObserver = NotificationCenter.default.publisher(for: .NSUndoManagerCheckpoint)
.onReceive(undoObserver, perform: { _ in
print(undoManager)
viewContext.undoManager = undoManager
})
Run Code Online (Sandbox Code Playgroud)
同样不幸的是,它唯一起作用的就是转到另一个视图并返回,然后 UndoManager 设置正确。有任何想法吗?我错过了一些明显的东西吗?
我正在尝试使用CloudKit查找用户记录ID.我已经确认帐户状态是CKAccountStatusAvailable.然后我试试这个:
[[CKContainer defaultContainer] fetchUserRecordIDWithCompletionHandler:^(CKRecordID *recordID, NSError *error) {
if (error == nil) {
NSLog(@"Got user record ID (no permission req): %@", recordID);
} else {
NSLog(@"Couldn't get user record ID, error=%@", error);
}
}];
Run Code Online (Sandbox Code Playgroud)
这不可避免地失败,结果如下:
(lldb) po error
<CKError 0x608000043990: "Not Authenticated" (9/1004); "Account couldn't get container scoped user id, no underlying error received">
(lldb) po [error userInfo]
{
NSDebugDescription = "CKInternalErrorDomain: 1004";
NSLocalizedDescription = "Account couldn't get container scoped user id, no underlying error received";
NSUnderlyingError = …Run Code Online (Sandbox Code Playgroud) 我的应用程序在CloudKit中几乎所有内容现在都会返回此错误:
<CKError 0x14ecff70: "Server Rejected Request" (15/2001); "Request failed with http status code 500">
(lldb) po [error userInfo]
{
CKDHTTPHeaders = {
Connection = close;
"Content-Length" = 0;
"X-Apple-Request-UUID" = "F8E4C91A-5F72-4792-9F13-BB5FBB10BA8E";
"X-Responding-Instance" = "ckdatabaseservice:32400203:mr11p24ic-ztbu11100101:8103:15B153:16274";
};
CKHTTPStatus = 500;
NSDebugDescription = "CKInternalErrorDomain: 2001";
NSLocalizedDescription = "Request failed with http status code 500";
NSUnderlyingError = "<CKError 0x14d5af70: \"Unknown Error\" (2001)>";
}
Run Code Online (Sandbox Code Playgroud)
任何想法为什么会发生这种情况?我很想把它归咎于临时的CloudKit服务器问题(这就是我想要解释错误500的方式)......但我不知道这是否合适.
我打算开发一个用于分享有关地理位置信息的应用程序(坐标,笔记,图片),一种寻宝游戏,我不明白是否有可能使用CloudKit在用户之间共享私人容器的一部分.如果是的话,我该怎么做?我需要在Reminders App中创建像Apple那样的东西,用户可以"邀请"其他用户并拥有一个公共列表,在每个人之间可以插入或编辑内容.
最终如果使用CloudKit无法做到这一点,我可以用Parse做到吗?
谢谢!
cloudkit ×10
core-data ×5
swift ×2
swiftui ×2
cloudkit-js ×1
icloud-drive ×1
ios ×1
ios14 ×1
javascript ×1
macos ×1