iCloud > iCloud Documents
- 準備: アプリ単位の ContainerID を設定
UIDocument
を継承したクラスを作成するcontents()
を overrideload()
を override
NSMetadataQuery
でファイルのURLを特定FileManager
を使用してファイルの読み書き
・・・という感じだが、使うことがあったときにもう少し詳しく見よう。。
swift
class MyDocument: UIDocument {
var fileContent: Data?
override func contents(forType typeName: String) throws -> Any {
return fileContent ?? Data()
}
override func load(fromContents contents: Any, ofType typeName: String?) throws {
if let data = contents as? Data, !data.isEmpty {
fileContent = data
}
}
}
swift
class ApplicationData: ObservableObject {
var document: MyDocument!
var metaData: NSMetadataQuery!
init() {
metaData = NSMetadataQuery()
metaData.predicate = NSPredicate(format: "%K == %@", NSMetadataItemFSNameKey, "myfile.dat")
metaData.searchScopes = [NSMetadataQueryUbiquitousDocumentsScope]
Task(priority: .high) {
let center = NotificationCenter.default
let name = NSNotification.Name.NSMetadataQueryDidFinishGathering
for await notification in center.notifications(named: name, object: metaData) {
if notification.name == name {
await createFile()
}
}
}
metaData.start()
}
@MainActor
func createFile() async {
if metaData.resultCount > 0 {
let file = metaData.result(at: 0) as! NSMetadataItem
let fileURL = file.value(forAttribute: NSMetadataItemURLKey) as! URL
document = MyDocument(fileURL: fileURL)
} else {
let manager = FileManager.default
if let fileURL = manager.url(forUbiquityContainerIdentifier: nil) {
let documentURL = fileURL.appendingPathComponent("Documents/myfile.dat")
document = MyDocument(fileURL: documentURL)
document.fileContent = Data()
if manager.fileExists(atPath: documentURL.path) {
let _ = await document.save(to: documentURL, for: .forOverwriting)
} else {
let _ = await document.save(to: documentURL, for: .forCreating)
}
}
}
}
@MainActor
func openDocument() async -> String {
let manager = FileManager.default
if let fileURL = manager.url(forUbiquityContainerIdentifier: nil) {
let documentURL = fileURL.appendingPathComponent("Documents/myfile.dat")
document = MyDocument(fileURL: documentURL)
let success = await document.open()
if success {
if let data = document.fileContent {
return String(data: data, encoding: .utf8) ?? ""
}
}
}
return ""
}
@MainActor
func saveDocument(text: String) async {
let manager = FileManager.default
if let fileURL = manager.url(forUbiquityContainerIdentifier: nil) {
let documentURL = fileURL.appendingPathComponent("Documents/myfile.dat")
if let data = text.data(using: .utf8) {
document.fileContent = data
let _ = await document.save(to: documentURL, for: .forOverwriting)
}
}
}
@MainActor
func closeDocument() async {
let _ = await document.close()
}
}
swift
struct EditDocumentView: View {
@EnvironmentObject var appData: ApplicationData
@Environment(\.dismiss) var dismiss
@State private var inputText: String = ""
var body: some View {
VStack {
HStack {
Button("Close") {
dismiss()
}
.padding()
Spacer()
Button("SAve") {
Task(priority: .high) {
await appData.saveDocument(text: inputText)
dismiss()
}
}
.padding()
}
GroupBox {
TextEditor(text: $inputText)
}
}
.task {
inputText = await appData.openDocument()
}
.onDisappear {
Task(priority: .background) {
await appData.closeDocument()
}
}
}
}
swift
@State private var editDocument: Bool = false
VStack {
Text("My Document")
.padding()
Button("Open Document") {
editDocument = true
}
.buttonStyle(.borderedProminent)
.padding()
}
.sheet(isPresented: $editDocument) {
EditDocumentView()
}
xml
<key>NSUbiquitousContainers</key>
<dict>
<key>iCloud.com.sugoi-user.SugoiApp</key>
<dict>
<key>NSUbiquitousContainerIsDocumentScopePublic</key>
<true/>
<key>NSUbiquitousContainerName</key>
<string>SugoiApp</string>
<key>NSUbiquitousContainerSupportedFolderLevels</key>
<string>Any</string>
</dict>
</dict>