Bring Core Data concurrency to Swift and SwiftUI

RSS for tag

Discuss the WWDC21 session Bring Core Data concurrency to Swift and SwiftUI.

View Session

Posts under wwdc21-10017 tag

23 Posts
Sort by:
Post marked as solved
1 Replies
125 Views
how do i get rid of this grey top row?  var body: some View {           NavigationView {     Form {       HStack {         Form {                      TextField("pH", text: $viewModel.pH)             .modifier(TextFieldClearButton(text: $viewModel.pH))           TextField("pCO2", text: $viewModel.pCO2)             .modifier(TextFieldClearButton(text: $viewModel.pCO2))                       TextField("HCO3", text: $viewModel.HCO3)             .modifier(TextFieldClearButton(text: $viewModel.HCO3))           TextField("Glu", text: $viewModel.Glu)             .modifier(TextFieldClearButton(text: $viewModel.Glu))                       Spacer()                             }.frame(width: /*@START_MENU_TOKEN@*/150.0/*@END_MENU_TOKEN@*/, height: 200).lineSpacing(/*@START_MENU_TOKEN@*/5.0/*@END_MENU_TOKEN@*/)                 Form {                       TextField("Na", text: $viewModel.Na)              .modifier(TextFieldClearButton(text: $viewModel.Na))            TextField("K", text: $viewModel.K)              .modifier(TextFieldClearButton(text: $viewModel.K))            TextField("Cl", text: $viewModel.Cl)              .modifier(TextFieldClearButton(text: $viewModel.Cl))            TextField("Alb", text: $viewModel.Alb)              .modifier(TextFieldClearButton(text: $viewModel.Alb))                     }.frame(width: /*@START_MENU_TOKEN@*/150.0/*@END_MENU_TOKEN@*/, height: /*@START_MENU_TOKEN@*/200.0/*@END_MENU_TOKEN@*/)          .lineSpacing(/*@START_MENU_TOKEN@*/5.0/*@END_MENU_TOKEN@*/)
Posted
by dtos11.
Last updated
.
Post not yet marked as solved
1 Replies
126 Views
I have 3 entities: Topic, Group and Word. Topic has a one-to-many relation with Group, and Group has a one-to-many relation with Word. From a list of words, I want to get the ones that belong to certain topic. That means, getting the group of the word and then the topic of the word. For a Word fetch request, I have NSPredicate(format: "group.topic = %@", topic). Where topic is the object I want to match word to. But this isn't working so I guess it isn't the right way of doing it. Does someone know how something like this could be done?
Posted Last updated
.
Post not yet marked as solved
1 Replies
126 Views
I'm having problems with NSPredicate. It started because for some conditions I got empty lists when I knew there was something in the model. I've made a lot of tests and I found that it fails when I use %@ (to have a variable). If I write the variable directly, it works fine. But in some situations, it works fine when I have a %@, but if I add a second variable with AND it gives again an empty list. I've checked that the context, the spelling are fine. Also, the objects do exist, since I get them by typing the variable directly. For some reason, I get an empty list in some situation (which are always the same situations, it doesn't happen randomly). I think the problem is that CoreData gives and error, so I get an empty list as the default. Does anyone know what could be happening?
Posted Last updated
.
Post not yet marked as solved
1 Replies
329 Views
I am using a database with NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType) Everything works fine, I save objects, read, and delete without problems. If set "-com.apple.CoreData.ConcurrencyDebug 1" : I save the object through the PerformAndWait block - ok I do fetch - receive an object, but its properties are empty (data = fault) and it crashes. (EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)) sample code: public final class  DatabaseCore {     private let persistentContainer: NSPersistentContainer     private var backgroundContext: NSManagedObjectContext!     private let queue: DispatchQueue public init() {         self.persistentContainer = Self.createPersistentContainer()         self.queue = queue         self.queue.async {             self.backgroundContext = Self.createNewBackgroundContext(container: self.persistentContainer)         } // Private     private static func createPersistentContainer() -> NSPersistentContainer {         let model = NSManagedObjectModel(contentsOf: Bundle.module.url(forResource: "TestModel", withExtension: "momd")!)         let container = NSPersistentContainer(name: "TestModel", managedObjectModel: model)         let description = NSPersistentStoreDescription()         description.url = URL(fileURLWithPath: "/dev/null")         container.persistentStoreDescriptions = [description]         container.loadPersistentStores(completionHandler: { (storeDescription, error) in             if let error = error as NSError? {                // print error             }         })         return container     } private static func createNewBackgroundContext(container: NSPersistentContainer) -> NSManagedObjectContext {         let context = container.newBackgroundContext()         context.mergePolicy = NSOverwriteMergePolicy         context.undoManager = nil         return context     } private static func saveContext(_ context: NSManagedObjectContext) {         context.performAndWait {             if !context.hasChanges { return }             do {                 try context.save()             } catch {                 // print error             }         }     } // Public public func upsert(_ block: @escaping (NSManagedObjectContext) -> Void, completion: (() -> Void)?) {         self.queue.async {             let context: NSManagedObjectContext! = self.backgroundContext             self.backgroundContext.performAndWait {                 block(context)                 Self.saveContext(context)             }             completion?()         }     } public func fetch<ResultType: NSFetchRequestResult>(_ request: NSFetchRequest<ResultType>, completion: @escaping ([ResultType]) -> Void) {         self.queue.async {             var result: [ResultType] = []             self.backgroundContext.performAndWait {                 do {                     result = try request.execute()                 } catch let error {                     // print error                 }             }             completion(result)         }     } } I set a breakpoint to result fetch func if set  "-com.apple.CoreData.ConcurrencyDebug 1": (lldb) po record <Test: 0x7b1400030070> (entity: Test; id: 0xbb200e8d680f1045 <x-coredata://1BFC3A95-3F7D-4A23-AD20-FDF23B575D73/CDLog/p1>; data: <fault>) (lldb) po record.value error: Execution was interrupted, reason: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0). The process has been returned to the state before expression evaluation. Without  "-com.apple.CoreData.ConcurrencyDebug 1", everything works correctly, without a crash. (lldb) po record <Test: 0x7b1400028c80> (entity: Test; id: 0xb29880bd32a57757 <x-coredata://1BFC3A95-3F7D-4A23-AD20-FDF23B575D73/CDLog/p1>; data: <fault>) (lldb) po record.value 0 How can this be fixed? Thank you! =) Xcode 13.3
Posted
by Arttem.
Last updated
.
Post not yet marked as solved
0 Replies
127 Views
I'm not sure if I'm missing something but the SortMenu view to which Scott inserted a reference at around 21:17 isn't shown anywhere in the video, nor is it part of the downloadable source code. I'd like to reproduce the sort menu shown in this example but it's strange that the code differs from the video that much.
Posted
by hal9ccc.
Last updated
.
Post not yet marked as solved
0 Replies
240 Views
I have a CoreData database, and I have attempted to migrate it to an app group to share it between my main app and a widget extension. The database seems that seems to be fetched by the app and the widget seem to be completely separate from each other. My CoreData code (persistence.swift) import CoreData struct PersistenceController {   static let shared = PersistenceController()   static var preview: PersistenceController = {     let result = PersistenceController(inMemory: true)     let viewContext = result.container.viewContext     let newUserData = Userdata(context: viewContext)     newUserData.hourly = 15.3     let newSession = Session(context: viewContext)     newSession.id = UUID()     newSession.start = Date()     newSession.end = Date()     do {       try viewContext.save()     } catch {       let nsError = error as NSError       fatalError("Unresolved error \(nsError), \(nsError.userInfo)")     }     return result   }()   let container: NSPersistentContainer   init(inMemory: Bool = false) {     container = NSPersistentContainer(name: "FManger")     let storeURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.omaribrahim-uchicago.FManger")!.appendingPathComponent("FManger.sqlite")     var defaultURL: URL?       if let storeDescription = container.persistentStoreDescriptions.first, let url = storeDescription.url {         defaultURL = FileManager.default.fileExists(atPath: url.path) ? url : nil       }     if defaultURL == nil {         container.persistentStoreDescriptions = [NSPersistentStoreDescription(url: storeURL)]       }     container.loadPersistentStores(completionHandler: { [unowned container] (storeDescription, error) in         if let error = error as NSError? {           fatalError("Unresolved error \(error), \(error.userInfo)")         }         if let url = defaultURL, url.absoluteString != storeURL.absoluteString {           let coordinator = container.persistentStoreCoordinator           if let oldStore = coordinator.persistentStore(for: url) {             do {               try coordinator.migratePersistentStore(oldStore, to: storeURL, options: nil, withType: NSSQLiteStoreType)             } catch {               print(error.localizedDescription)             }             // delete old store             let fileCoordinator = NSFileCoordinator(filePresenter: nil)             fileCoordinator.coordinate(writingItemAt: url, options: .forDeleting, error: nil, byAccessor: { url in               do {                 try FileManager.default.removeItem(at: url)               } catch {                 print(error.localizedDescription)               }             })           }         }       })   } } My Widget data constructor and main function import WidgetKit import SwiftUI import Intents struct Provider: IntentTimelineProvider {       func placeholder(in context: Context) -> SimpleEntry {     SimpleEntry(date: Date(), data: .previewData, error: false, configuration: ConfigurationIntent())   }   func getSnapshot(for configuration: ConfigurationIntent, in context: Context, completion: @escaping (SimpleEntry) -> ()) {     let entry = SimpleEntry(date: Date(), data: .previewData, error: false, configuration: configuration)           completion(entry)   }   func getTimeline(for configuration: ConfigurationIntent, in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {     var entries: [SimpleEntry] = []     @FetchRequest(       sortDescriptors:[NSSortDescriptor(key: "start", ascending: false)],       animation: .default)     var sessions: FetchedResults<Session>           if (sessions.count > 0) {       let checkedIn = sessions[0].end != nil       let totalMinutes = totalMinutes(sessions: sessions)       var auxMinutes = 0.0       if (checkedIn) {         auxMinutes = timeBetween(fromDate: sessions[0].start!, toDate: Date())       }               let currentDate = Date()       for i in 0 ..< 5 {         let entryDate = Calendar.current.date(byAdding: .hour, value: i, to: currentDate)!                   let cSession = fromMinutes(minutes: (Double(i) * 60) + auxMinutes)                   let widgetData = SimpleEntry.PayData(currentSession: cSession,                            grossTotal: totalMinutes * 15.3 + cSession,                            paycheckDay: Date() + (7 * 24 * 60 * 60),                            checkedIn: checkedIn)                   let entry = SimpleEntry(date: entryDate,                     data: widgetData,                     error: false,                     configuration: configuration)                   entries.append(entry)       }     }     else {       let entry = SimpleEntry(date: Date(),                   data: .error,                   error: true,                   configuration: configuration)       entries.append(entry)     }     let timeline = Timeline(entries: entries, policy: .atEnd)     completion(timeline)   } } @main struct Widgets: Widget {   let kind: String = "Widgets"   let persistenceController = PersistenceController.shared   var body: some WidgetConfiguration {     IntentConfiguration(kind: kind, intent: ConfigurationIntent.self, provider: Provider()) { entry in       WidgetsEntryView(entry: entry)         .environment(\.managedObjectContext, persistenceController.container.viewContext)     }     .configurationDisplayName("Pay Tracker")     .description("Check your current shift's earning, total earnings, and the date of your next payment in a glance.")   } } I am pretty sure I did something wrong, but what is it?
Posted Last updated
.
Post not yet marked as solved
1 Replies
1.1k Views
I’m currently migrating my app to use the concurrency model in Swift. I want to serialize Tasks to make sure they are executed one after the other (no paralellism). In my use case, I want to listen to notifications posted by the NotificationCenter and execute a Task every time a new notification is posted. But I want to make sure no previous task is running. It's the equivalent of using an OperationQueue with maxConcurrentOperationCount = 1. For example, I’m using CloudKit with Core Data in my app and I use persistent history tracking to determine what changes have occurred in the store. In this Synchronizing a Local Store to the Cloud Sample Code, Apple uses an operation queue for handling history processing tasks (in CoreDataStack). This OperationQueue has a maximum number of operations set to 1. private lazy var historyQueue: OperationQueue = { let queue = OperationQueue() queue.maxConcurrentOperationCount = 1 return queue }() When a Core Data notification is received, a new task is added to this serial operation queue. So if many notifications are received, they will all be performed one after the other one in a serial way. @objc func storeRemoteChange(_ notification: Notification) { // Process persistent history to merge changes from other coordinators. historyQueue.addOperation { self.processPersistentHistory() } } In this Loading and Displaying a Large Data Feed Sample Code, Apple uses Tasks to handle history changes (in QuakesProvider). // Observe Core Data remote change notifications on the queue where the changes were made. notificationToken = NotificationCenter.default.addObserver(forName: .NSPersistentStoreRemoteChange, object: nil, queue: nil) { note in Task { await self.fetchPersistentHistory() } } I feel something is wrong in the second project as Tasks could happen in any order, and not necessarily in a serial order (contrary to the first project where the OperationQueue as a maxConcurrentOperationCount = 1). Should we use an actor somewhere to make sure the methods are serially called? I thought about an implementation like this but I’m not yet really comfortable with that: actor PersistenceStoreListener { let historyTokenManager: PersistenceHistoryTokenManager = .init() private let persistentContainer: NSPersistentContainer init(persistentContainer: NSPersistentContainer) { self.persistentContainer = persistentContainer } func processRemoteStoreChange() async { print("\(#function) called on \(Date.now.formatted(date: .abbreviated, time: .standard)).") } } where the processRemoteStoreChange method would be called by when a new notification is received (AsyncSequence): notificationListenerTask = Task { let notifications = NotificationCenter.default.notifications(named: .NSPersistentStoreRemoteChange, object: container.persistentStoreCoordinator) for await _ in notifications { print("notificationListenerTask called on \(Date.now.formatted(date: .abbreviated, time: .standard)).") await self.storeListener?.processRemoteStoreChange() } }
Posted
by alpennec.
Last updated
.
Post not yet marked as solved
0 Replies
244 Views
I'm trying to delay when the contextMenu appears because I have a drag gesture over the same view which causes a confuse user experience. My code: … Text(exampleText) .contextMenu { delay() // Menus here } .gesture( DragGesture() .onEnded( { end in switch exampleTextAlignment { case .leading: if end.translation.width > 0 { exampleTextAlignment = .center onContextMenuAlignment = .top } case .center: if end.translation.width < 0 { exampleTextAlignment = .leading onContextMenuAlignment = .topLeading } else if end.translation.width > 0 { exampleTextAlignment = .trailing onContextMenuAlignment = .topTrailing } case .trailing: if end.translation.width < 0 { exampleTextAlignment = .center onContextMenuAlignment = .top } } } ) ) … where delay() is: … private func delay() async { try? await Task.sleep(nanoseconds: UInt64(secondsHere * Double(NSEC_PER_SEC))) hasTimeElapsed = true } … Xcode v.13.2 and iOS v.15.2. Here's a more detailed question: https://stackoverflow.com/questions/71201562/delay-contextmenu-on-swiftui
Posted Last updated
.
Post not yet marked as solved
2 Replies
736 Views
Dear: Use core data to store super long strings. After storage, the strings are incomplete. Xcode tips: CoreData: debug: PostSaveMaintenance: fileSize 30409752 greater than prune threshold CoreData: annotation: PostSaveMaintenance: wal_checkpoint(TRUNCATE)  help me?
Posted
by aiyowei.
Last updated
.
Post not yet marked as solved
1 Replies
504 Views
I am presenting a list of Items which are sections by the categoryIdentifier property. My app uses CloudKit. When I add change the categoryIdentifier for an item it is display in the correct section and other running instances of the app do the same. When restarting the app some items are grouped under an incorrect section, but the cstegoryIdentifier within the item is still as it was set. My question is what I'm doing wrong that upon restart the organization is incorrect. In case it matters, I'm setting this in the container:         container.viewContext.automaticallyMergesChangesFromParent = true As an aside: It seems necessary to make the sectioning type optional (as is the case in the underlying entity) like this SectionedFetchResults<String?, Item> Though the examples don't seem to need this. struct ContentView: View {     @Environment(\.managedObjectContext) private var viewContext     @State private var isShowingItem = false     @State private var isAddingItem = false          @SectionedFetchRequest(         sectionIdentifier: \.categoryIdentifier,         sortDescriptors: [NSSortDescriptor(keyPath: \Item.name, ascending: true)],         animation: .default) private var sectionedItems: SectionedFetchResults<String?, Item>          var body: some View {         NavigationView {             List {                 ForEach(sectionedItems) { section in                     Section(header: Text(Category.nameForId(section.id, context: viewContext)).font(.headline)) {                         ForEach(section) { item in                             NavigationLink(destination: ItemInputView(item: item, category: Category.get(identifier: item.category, context: viewContext))) {                                 Text(item.getName())                             }                         }                     }                 }             }                          .navigationTitle("Foo")             .sheet(isPresented: $isAddingItem) {                 ItemInputView(item: nil, category: Category.getDefault(context: viewContext))             }         }         .navigationViewStyle(.stack)     } }
Posted
by spiff.
Last updated
.
Post not yet marked as solved
2 Replies
551 Views
I am working on a couple of Multiplatform apps that use a very similar 3 column layout - sidebar menu (or tabs for sizeClassHorizontal == .compact), with a master list under each menu option and detail view based upon master list selection. The apps use Core Data framework and NSPersistentCloudKitContainer for backup and syncing across a user's devices. The apps use Codegen = Class Definition and I write extensions for each entity to prepare convenience methods, properties, comply with generic protocol conformance. I am learning how to retrofit sectioned fetch requests into each master List. Generally this is straightforward and I'm really happy with the result. However, one particular master list is based upon an hierarchical data structure and I have investigated using the children: parameter in List to successfully create an hierarchical list. So to be clear, the following code is based upon @FetchRequest var gardens: FetchedResults<Garden> (not a sectioned fetch request) and works well... extension Garden {     var arrayGardenChildren: [Garden]? {         let setGardenChildren = self.children as? Set<Garden> ?? []         return setGardenChildren.sorted(by: { $0.name ?? " NO NAME" < $1.name ?? " NO NAME" })     } } and @FetchRequest(sortDescriptors: [ SortDescriptor(\.name, order: .forward), SortDescriptor(\.timeStampCreated, order: .reverse)           ],           animation: .default ) var gardens: FetchedResults<Garden> and private func arrayGardens() -> [Garden] {     return Array(gardens) } and List(arrayGardens(), children: \.arrayGardenChildren) { garden in NavigationLink(destination: GardenDetail(...),                    tag: garden.uuID!.uuidString,                    selection: $appData.selectedGardens ) { GardenRow(garden: garden,                   selected: garden.uuID?.uuidString == appData.selectedGardens) } } ... perhaps obviously from this code, I am forced to convert the FetchedResults to an Array and the entity's children from an NSSet to a sorted Array - no big deal - a little extra code but it works fine and I'm happy. On first impressions, the lists look great on macOS and iOS, however there are a few downsides to this implementation: expansion state cannot be set as @SceneStorage or therefore controlled as per the sidebar menu in the Apple Developer "Garden" sample app for the WWDC21 code-along "Building a Great Mac App with SwiftUI"; for both iOS and macOS, there are no section headers, which are my preference when the list becomes longer; for both iOS and macOS, the bottom level items in each hierarchy tree include a disclosure chevron despite that those items have no children; on iOS, due to the navigation link for the detail view, there are double chevrons at the trailing edge of each row... the inner chevron is the link to the detail view and the outer chevron is the disclosure indicator. This appearance is not ideal and there are a few of ways I can adjust the UI to suit, but include the raw / unedited constraint here for clarity. So I have continued experimenting with a sectioned fetch request. As a starting point, the following code works well... extension Garden {     @objc var sectionNameParentNil: String {         return self.name?.filter({ _ in self.parent == nil }) ?? "NO NAME"     } } where each instance of the entity Garden has two relationships that allow the parent child arrangement, a To-One relationship named parent and a To-Many relationship named children (both with destination = Garden). ...and... SectionedFetchRequest(sectionIdentifier: \.sectionNameParentNil, sortDescriptors: [ SortDescriptor(\.name, order: .forward), SortDescriptor(\.timeStampCreated, order: .reverse) ], animation: .default) ) var gardens: SectionedFetchResults<String, Garden> ...and... List { ForEach(gardens) { section in Section(header: Text(section.id)) { ForEach(section) { garden in NavigationLink(destination: GardenDetail(...),                      tag: garden.uuID!.uuidString,                      selection: $appData.selectedGardens                 ) {                     GardenRow(garden: garden,                         selected: garden.uuID?.uuidString == appData.selectedGardens)                 }         } } } } This is a good start and works well but only presents the top level elements of the hierarchical data set (where parent = nil). I want to be able to include all children for each top level "Garden" and also mimic the expandable / collapsable function demonstrated in the above noted sample app. I've done some googling and read a few articles, including "Displaying recursive data using OutlineGroup in SwiftUI" by one of my favourite SwiftUI bloggers. Based upon my research and reading, I begun by replacing the second ForEach line in the above block with... OutlineGroup(section, children: \Garden.children ?? nil) { garden in The compiler complains "Cannot convert value of type 'ReferenceWritableKeyPath<Garden, NSSet?>?' to expected argument type 'KeyPath<SectionedFetchResults<String, Garden>.Section.Element, SectionedFetchResults<String, Garden>.Element?>' (aka 'KeyPath<Garden, Optional<SectionedFetchResults<String, Garden>.Section>>')". My compiler interpretation skills are intermediate at best, but this is beyond me. I've attempted a few different combinations to attempt to provide a suitable type, but all my attempts to date have caused compiler errors that I am not able to resolve. I'll try to include a few more below. OutlineGroup(section, children: \.arrayGardenChildren) { garden in causes the following compiler error Key path value type '[Garden]?' cannot be converted to contextual type 'SectionedFetchResults<String, Garden>.Element?' (aka 'Optional<SectionedFetchResults<String, Garden>.Section>') So from these messages I somehow need to provide a key path for SectionedFetchResults<String, Garden>.Element. The question for me is how? Any suggestions please?
Posted Last updated
.
Post not yet marked as solved
0 Replies
581 Views
I am working on a SwiftUI project and in a subview I use @FetchRequest to fetch data from CoreData. I have a menu to let user select which data to fetch, and by default I want to fetch all datas. The problem is when user open the menu and select a category then it refetch the data, it's correct and when user close the menu, the nsPredicate that the user have given will disappear and switch to the default predicate. I tried to write the same pattern code on 'EarthQuake' sample app, it has the same problem. And here is the code: List(selection: $selection) {                 ListView(search: $searchText)             }             .background(toggle ? Color.red.opacity(0.01) : nil)             .toolbar {                 ToolbarItem(placement: .bottomBar) {                     Button {                         toggle.toggle()                     } label: {                         Text("Toggle")                     }                 }             }             .searchable(text: $searchText) ListView: struct ListView: View {     @FetchRequest(sortDescriptors: [SortDescriptor(\.time, order: .reverse)]) // predicate: nil     private var quakes: FetchedResults<Quake>     @Binding var search: String     var body: some View {         ForEach(quakes, id: \.code) { quake in             NavigationLink(destination: QuakeDetail(quake: quake)) {                 QuakeRow(quake: quake)             }         }         .onChange(of: search) { newValue in             quakes.nsPredicate = newValue.isEmpty ? nil : NSPredicate(format: "place CONTAINS %@", newValue)         }     } } I can filter data by typing in the search field but when I click on Toggle Button, it may refresh the ParentView which cause the @fetchRequest to update and nsPredicate return to nil. Is this a bug? Or maybe my understand was wrong. And is there any good suggestions?
Posted Last updated
.
Post not yet marked as solved
3 Replies
758 Views
I have a SectionedFetchRequest that almost works as expected. My data model has two Entities (Item and Attribute). Both entities have a name attribute and an order attribute. The Attribute entity has a to-One relationship to an Item called item. The Attribute entity also has a computed property:     @objc var sectionName: String {         get { return self.item.name } The SectionedFetchRequest's sectionIdentifier key is \Attribute.sectionName and the sortDescriptors keys are \Attribute.item.order and then \Attribute.order. This sorts groups of Attribute's into Sections ordered by the Attribute item's order property. Each section is then ordered by the Attribute's own order property. As expected, when the order property of any Attribute object in the results changes, that section of the View is updated to reflect the change. However, if any of the Attribute's related Item order properties change, the View is not updated. It almost seems like SectionedFetchRequest is handling the NSManagedObjectContextDidSave notifications for changes to Attribute objects, but ignoring changes to Item objects that that should cause the results order to be changed and therefore the View to be updated. Is this a bug in SectionedFetchRequest or is there a direct way that I can get the SectionedFetchRequest to change its state so SwiftUI can update the View as expected? When I make a change to an Item's order, I can force the results to be updated by dynamically changing the nsPredicate with something that's different, but something that does not actually change the results. However, it seems like there should be a more appropriate way to force the SectionedFetchRequest to update the order of the Sections even if no changes are made to the actual Attribute objects that fetched.
Posted Last updated
.
Post not yet marked as solved
1 Replies
453 Views
Hi all, Looking into the new @SectionedFetchRequest in SwiftUI 3 and it's really awesome. Thx! But how can I keep track of the total number of records fetched now that they are separated into sections? Can't find anything useful in the docs. Want to update the counter inte the Quakes sample app now that I'm using @SectionedFetchRequest instead of @FetchRequest. Thx in advance / Jörgen, Bitfield
Posted
by jogga.
Last updated
.
Post not yet marked as solved
3 Replies
1.3k Views
Im not sure why, but my tableView.delegate & tableView.data are returning errors "Reference to member 'delegate' cannot be resolved without a contextual type" "Reference to member 'dataSource' cannot be resolved without a contextual type" I've done everything around my code to see why I am getting these errors but I do not understand. My code is below import UIKit @MainActor class HomeViewController: UIViewController, UITableViewDataSource, UITableViewDelegate { @IBOutlet weak var TableView: UITableView! public var meals = [Meal]() override func viewDidLoad() { super.viewDidLoad() fetchJSON { print("APICompleted") } tableView.delegate = self //error// tableView.dataSource = self //error// } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return meals.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = UITableViewCell(style: .subtitle , reuseIdentifier: nil) cell.textLabel?.text = meals[indexPath.row].strMeal.capitalized return cell } func fetchJSON(completed: @escaping () -> ()) { let jsonUrlString = "https://www.themealdb.com/api/json/v1/1/filter.php?c=Beef" guard let url = URL(string: jsonUrlString) else { print("invalid url string lel") return } print("Select a meal to make today!") URLSession.shared.dataTask(with: url) { data, response, error in guard let data = data else { return } do { let decoder = JSONDecoder() let mealDetailResponse = try decoder.decode(MealDetailResponse.self, from: data) for meal in mealDetailResponse.meals { print("The Meal is \(meal)") DispatchQueue.main.async { completed() } } }catch { print(error) } }.resume() } }
Posted
by Wenh08.
Last updated
.
Post not yet marked as solved
0 Replies
280 Views
I have a scheduled function uses a private queue context to fetch objects from CoreData and uploads them to a server and deletes the fetched objects if successfully uploaded. The upload function is an async function that uses URLSession. context.perform { do { let fetchRequest = NSFetchRequest<CustomEntity> fetchRequest = CustomEntity.fetchRequest() let objects = try context.fetch(fetchRequest) let data = JSONSerialization.data(withJsonObject: objects, options: []) // await uploadToServer(data) // delete after successful upload: objects.forEach(context.delete) try context.save() } catch let error { } } However, this doesn't seem legal though. xcode gives me an error: 'async' call in a function that does not support concurrency. Stuck on how to invoke the async function within the context.perform { } block
Posted
by alfonce.
Last updated
.
Post not yet marked as solved
1 Replies
395 Views
Hi, I am using a child NSManagedContext trying to isolate changes to a NSManagedObject from changes done to the same object in the parent NSManagedObjectContext. This works fine for normal properties, but any changes to relationships performed on the object in the parent context will show up immediately in the child object as well. Is this the intended behavior? If yes is there a way to create an "isolated" version of an NSManagedObject? Thanks in advance for any hints! Cheers, Michael
Posted
by milutz.
Last updated
.
Post marked as solved
2 Replies
686 Views
I am learning how to implement the new @SectionedFetchRequest with my Core Data object graph. Here is my call...     @SectionedFetchRequest(         sectionIdentifier: \.sectionDay,         sortDescriptors: [             SortDescriptor(\.dateCommences, order: .reverse),             SortDescriptor(\.timeStampCreated, order: .reverse)],         animation: .default)     private var events: SectionedFetchResults<String, PTG_Event> where PTG_Event is the Core Data entity of results that I am expecting to be returned, sectionDay is a convenience method that is prepared in an extension to PTG_Event. I have a user setting to display archived records (or not) using the entity attribute isArchived and I am attempting to take advantage of the @AppStorage wrapper as follows...     @AppStorage("preference_displayArchived") var kDisplayArchived = true I cannot include a predicate in my sectioned fetch request, e.g.         predicate: NSPredicate(format: "isArchived == %@", NSNumber(booleanLiteral: kDisplayArchived)), ... because I receive the error ... Cannot use instance member 'kDisplayArchived' within property initializer; property initializers run before 'self' is available I understand this, but how do I create a dynamic reference to the app storage wrapper? I am determined to figure out an easy method to use the user setting value preference_displayArchived in the sectioned fetch request, so I have also attempted to hack a solution together using the method shown in #wwdc21-10017 for preparing a query for the .searchable modifier, but have been so far unsuccessful in figuring out how to squeeze that into my List code.     @State private var displayArchived = false     var queryArchived: Binding<Bool> {         Binding {             displayArchived         } set: { newValue in             displayArchived = newValue             events.nsPredicate = newValue == false ? nil : NSPredicate(format: "isArchived == %@", NSNumber(booleanLiteral: kDisplayArchived))         }     } Any suggestions?
Posted Last updated
.
Post not yet marked as solved
0 Replies
557 Views
In the code below you can see the error and the code used in my xxApp.swift folder. I was creating Sign In and a Sign Up function, and everything worked very well, but then I got this error when clicking on the register button. If you need more code just let me know, thanks in advance! Here is the code of the @main : import Firebase final class AppDelegate: NSObject, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -&gt; Bool { FirebaseApp.configure() return true } final class AppDelegate: NSObject, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -&gt; Bool { FirebaseApp.configure() return true }`final class AppDelegate: NSObject, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -&gt; Bool { FirebaseApp.configure() return true } } @main //"Thread 1: EXC_BAD_ACCESS (code=2, address=0x7ffee1a57ff0)" struct PSMAApp: App { @UIApplicationDelegateAdaptor(AppDelegate.self) var delegate @StateObject var sessionService = SessionServiceImpl() var body: some Scene { WindowGroup { NavigationView{ switch sessionService.state { case .loggedIn: HomeView() .environmentObject(sessionService) case .loggedOut: LoginView() } } } } }
Posted Last updated
.
Post not yet marked as solved
0 Replies
383 Views
I have an app similar to a Cooking recipes style app. I need to initialize the Coredata entity with some default recipes during the app 1st launch. The user can change this later. I Assume this should be done via background operations. From where should this initializer function be called? Is there any official doc/ guidance regarding the correct way of implementing this in swiftUI?
Posted
by tbodurian.
Last updated
.