Как создать локальный объект из CKRecord и добавить его в массив для данных NSTableView

Я работаю над проектом приложения для заметок для macOS с облачными возможностями, в частности, загружаю заметку другого человека с учетом заметок «CloudID», которое является просто уникальным именем, которое облачная база данных дает записи, когда заметка загружается в облако. Я использую базу данных sqlite для локального хранения данных и базу данных cloudKit для общедоступного хранилища данных. Когда я тестирую функцию загрузки, она правильно добавляет данные в базу данных sqlite, но локальный объект, который я добавляю в свой notesArray, который используется для заполнения NSTableView на моей домашней странице, не изменяется.

Вот код:

@IBAction func downloadNoteFromCloud(_ sender: Any) {
    // 1.) check to make sure text field isn't empty
    if (noteIDTextField.stringValue == "") {
        noteIDTextField.stringValue = "Please enter the desired note's cloudID"
    }
    
    // 2.) query the note with the given cloudID
    
    // make note object for the downloaded note bc of scope issues
    var downloadedNote = Note(0, "", "")
    
    //sets cloudDB to the public cloud database
    let container = CKContainer.default()
    let cloudDB = container.publicCloudDatabase
    
    let noteRecordID = CKRecord.ID(recordName: noteIDTextField.stringValue)
    
    // returns a CKRecord
    cloudDB.fetch(withRecordID: noteRecordID) { record, error in
        if let error = error {
            // Handle error
            print(error)
            return
        }
        // Record fetched successfully
        if let noteRecord = record {
            // set the values of the downloadedNote obj equal the the values of the noteRecord
            downloadedNote.setValues((notesArray.count), noteRecord["Title"] as! String, noteRecord["Body"] as! String)
            
            // add to local database ~ this works
            do {
                let path = NSSearchPathForDirectoriesInDomains(
                    .applicationSupportDirectory, .userDomainMask, true
                ).first! + "/" + Bundle.main.bundleIdentifier!

                // create parent directory iff it doesn’t exist
                try FileManager.default.createDirectory(
                atPath: path, withIntermediateDirectories: true, attributes: nil
                )
                
                //connect to DB
                let db = try Connection("\(path)/db.sqlite3")
                //Define the Notes Table and its Columns
                let notes = Table("Notes")
                //ID is primary key so it doesn't need to be defined for inserts
                let title = Expression<String>("Title")
                let body = Expression<String>("Body")
                
                try db.run(notes.insert(title <- downloadedNote.title, body <- downloadedNote.body))
            }
            catch {
                print(error)
            }
        }
    }
    // append downloadedNote to notesArray
    notesArray.append(downloadedNote)
    
    //Send Notification to reload the tableView data
    NotificationCenter.default.post(name: NSNotification.Name(rawValue: "load"), object: nil)
    
    //Return to home page
    self.view.window?.close()
}

Я предполагаю, что это проблема области действия, и я попытался переместить функцию добавления, и я попытался сделать исходное объявление downloadNote необязательным типом, который не инициализируется следующим образом: var downloadedNote: Note?, а затем инициализировал его внутри функции выборки вот так: downloadedNote = Note(id: notesArray.count, title: noteRecord["Title"] as! String, body: noteRecord["Body"] as! String) ни один из них не работал правильно. Самое близкое, что я заставил его работать, - это то, как сейчас работает код. Пожалуйста, дайте мне знать, где я ошибся и как это исправить. Большое спасибо за любую помощь!

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
26
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

CloudKit работает асинхронно. Переместите код для уведомления и перезагрузите таблицу в замыкание.

Заменять

           try db.run(notes.insert(title <- downloadedNote.title, body <- downloadedNote.body))
        }
        catch {
            print(error)
        }
    }
}
// append downloadedNote to notesArray
notesArray.append(downloadedNote)

//Send Notification to reload the tableView data
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "load"), object: nil)

//Return to home page
self.view.window?.close()

с

           try db.run(notes.insert(title <- downloadedNote.title, body <- downloadedNote.body))

           DispatchQueue.main.async {
               // append downloadedNote to notesArray
               notesArray.append(downloadedNote)

               //Send Notification to reload the tableView data
               NotificationCenter.default.post(name: NSNotification.Name(rawValue: "load"), object: nil)

               //Return to home page
               self.view.window?.close()
           }
        }
        catch {
            print(error)
        }
    }
}

И создайте также новую заметку внутри закрытия. вопросы масштаба больше нет.


Примечание:

NSSearchPathForDirectoriesInDomains пахнет объективный и устарел. Используйте API, связанный с FileManager URL

do {
    let fm = FileManager.default
    let applicationSupportURL = try fm.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
    let applicationSupportBundleURL = applicationSupportURL.appendingPathComponent(Bundle.main.bundleIdentifier!)
    
    if !fm.fileExists(atPath: applicationSupportBundleURL.path) {
        // create parent directory iff it doesn’t exist
        try fm.createDirectory(at: applicationSupportBundleURL, withIntermediateDirectories: true, attributes: nil)
    }
    let dbPath = applicationSupportBundleURL.appendingPathComponent("db.sqlite3").path
    
    //connect to DB
    let db = try Connection(dbPath)
    ...

Я попробовал это, и это дало мне ошибку «Модификации механизма компоновки не должны выполняться из фонового потока после того, как к нему был получен доступ из основного потока». поэтому, пожалуйста, дайте мне знать, что вызывает эту проблему

JonGrimes20 16.03.2022 16:48

Пожалуйста, смотрите редактирование. Вы должны отправить код, связанный с пользовательским интерфейсом, в основной поток.

vadian 16.03.2022 16:51

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