Post

Replies

Boosts

Views

Activity

Does anyone know where I can get an official StoreKit 1 example code from Apple?
We wish to implement in-app purchase for our app, which is currently targeting 14.3 The latest StoreKit 2, is only available for iOS 15 We wish to study how should we implement such, by looking at official code example of StoreKit 1. However, the current posted code at Apple site, is only available for StoreKit 2 - https://developer.apple.com/documentation/storekit/in-app_purchase/implementing_a_store_in_your_app_using_the_storekit_api Does anyone have any idea, where can I get the official StoreKit 1 code example, from Apple? Thanks.
0
0
263
Apr ’22
Why we need to use NSPersistentHistoryTransaction if NSFetchedResultController able to update UI correctly?
I still fail to understand, what is the problem NSPersistentHistoryTransaction is trying to solve, in the CoreDataCloudKitDemo WWDC 2019 "Using Core Data with CloudKit" https://github.com/software123inc/CoreDataCloudKitDemo/blob/master/CoreDataCloudKitDemo/DataProvider/CoreDataStack.swift#L161 I want to see, what problem will occur, if processPersistentHistory is not executed. By making the processPersistentHistory empty, I try to do the following testing. Run 2 simulators simultaneously in the same machine. Add an item to simulator A. Since, there is no way for simulator B to receive push notification, I press the home button for simulator B. In simulator B, I tap on the app icon to launch the app again. In simulator B, I can observe controllerDidChangeContent is being called. My guess is that, because the backed SQLite is seamlessly updated by CloudKit background task, NSFetchedResultController will be notified the SQLite DB change, and subsequently update the UI. Check the "Download CloudKit Changes into Core Data" of https://developer.apple.com/documentation/coredata/mirroring_a_core_data_store_with_cloudkit/syncing_a_core_data_store_with_cloudkit In simulator B, due to controllerDidChangeContent is being triggered correctly, I can observe the UI change perform by NSFetchResultController without issue. Hence, I am not clear, on what problem processPersistentHistory is trying to solve in the demo code. May I know what kind of test case I can perform, to understand the problem solved by processPersistentHistory? Based on "Integrate Store Changes Relevant to the Current View" https://developer.apple.com/documentation/coredata/mirroring_a_core_data_store_with_cloudkit/syncing_a_core_data_store_with_cloudkit Your app receives remote change notifications when the local store updates from CloudKit. However, it’s unnecessary to update your UI in response to every notification, because some changes may not be relevant to the current view. Analyze the persistent history to determine whether the changes are relevant to the current view before consuming them in the user interface. Inspect the details of each transaction, such as the entity name, its updated properties, and the type of change, to decide whether to act. For more information about persistent history tracking, see Consuming Relevant Store Changes. This part is getting confusing. Our NSFetchedResultController is receiving relevant entity change event due to SQLite, and subsequently able to update the UI correct. If that is so, why do we still need persistent history?
1
0
347
Apr ’22
Is using CoreData + CloudKit to store text notes, and iCloud Document to store note image attachments as image files a good design approach?
Is using CoreData + CloudKit to store text notes and iCloud Document to store note image attachments as image files a good design approach? Currently, I have almost finished implementing the app to store text notes as Core Data and note image attachments as image files. I like to provide iCloud storage support to the app. I come across a few app examples https://www.raywenderlich.com/13219461-getting-started-with-core-data-and-cloudkit https://developer.apple.com/documentation/coredata/synchronizing_a_local_store_to_the_cloud Both examples are using CoreData + CloudKit to store the image as SQLite blob binary data which CoreData will perform such task automatically) I'm aware that when storing the binary image into CoreData, CoreData is smart enough to choose either to store it as a binary blob in SQLite, or an external file. However, I am a little skeptical about such an approach We are using Kingfisher for smooth image loading in the collection view. If the image data are not in a regular flat-file, how can we integrate CoreData's blob data with Kingfisher? Storing images in CoreData seems like a black box. If something goes wrong in between, it is hard to debug where and how goes wrong. We like to provide alternative cloud storage (using cloud S3 storage to store SQLite files and multiple images) for the app. So, saving the image as flat files will make such an effort easier. Some related discussion on storing the image in DB vs flat files - https://stackoverflow.com/questions/3748/storing-images-in-db-yea-or-nay I would prefer Only use CoreData + CloudKit to store the text note and file path. The image file will store in both the app folder and the iCloud document folder (so that it syncs seamlessly to iCloud). If the required images are not in the app folder (App uninstall, then re-install), the app will try to copy the image file from the iCloud document I was wondering, anyone of you has tried such a design in your app? Do you find it is a good approach based on your experience? Thanks.
2
0
915
Apr ’22
Asynchronous read in CoreData - Difference in using newBackgroundContext + FetchRequest vs newBackgroundContext + NSAsynchronousFetchRequest?
It seems there are 2 ways to perform asynchronous read in CoreData, without blocking main thread UI. newBackgroundContext + FetchRequest Source : https://www.advancedswift.com/core-data-background-fetch-save-create/ // Create a new background managed object context let context = persistentContainer.newBackgroundContext() // If needed, ensure the background context stays // up to date with changes from the parent context.automaticallyMergesChangesFromParent = true // Perform operations on the background context // asynchronously context.perform { do { // Create a fetch request let fetchRequest: NSFetchRequest<CustomEntity> fetchRequest = CustomEntity.fetchRequest() fetchRequest.fetchLimit = 1 let objects = try context.fetch(fetchRequest) // Handle fetched objects } catch let error { // Handle error } } newBackgroundContext + NSAsynchronousFetchRequest Source: https://www.marcosantadev.com/coredata_crud_concurrency_swift_2/ let privateManagedObjectContext = persistentContainer.newBackgroundContext() // Creates a fetch request to get all the dogs saved let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Dog") // Creates `asynchronousFetchRequest` with the fetch request and the completion closure let asynchronousFetchRequest = NSAsynchronousFetchRequest(fetchRequest: fetchRequest) { asynchronousFetchResult in // Retrieves an array of dogs from the fetch result `finalResult` guard let result = asynchronousFetchResult.finalResult as? [Dog] else { return } // Dispatches to use the data in the main queue DispatchQueue.main.async { // Do something } } do { // Executes `asynchronousFetchRequest` try privateManagedObjectContext.execute(asynchronousFetchRequest) } catch let error { print("NSAsynchronousFetchRequest error: \(error)") } However, note that, the above code will unfortunately cause fatal error, if I were to enable flag -com.apple.CoreData.ConcurrencyDebug 1. So far, I do not have a good solution to such. For more detail, please refer to https://developer.apple.com/forums/thread/697718 ? May I know, what is the difference among newBackgroundContext + FetchRequest vs newBackgroundContext + NSAsynchronousFetchRequest? How should I choose one over another? Thank you.
0
0
1.3k
Dec ’21
Why I am getting Multithreading_Violation_AllThatIsLeftToUsIsHonor for this simplest NSAsynchronousFetchRequest use case?
I want to start learning to use NSAsynchronousFetchRequest by referring to  https://www.marcosantadev.com/coredata_crud_concurrency_swift_2/ I have the simplest use case of NSAsynchronousFetchRequest NSAsynchronousFetchRequest // Call from UI main thread func X() { let fetchRequest = NSFetchRequest<NSPlainNote>(entityName: "NSPlainNote") let asynchronousFetchRequest = NSAsynchronousFetchRequest(fetchRequest: fetchRequest) { asynchronousFetchResult in guard let result = asynchronousFetchResult.finalResult as? [NSPlainNote] else { return } } let coreDataStack = CoreDataStack.INSTANCE // backgroundContext created via persistentContainer.newBackgroundContext() let backgroundContext = coreDataStack.backgroundContext backgroundContext.perform { do { try backgroundContext.execute(asynchronousFetchRequest) } catch let error { backgroundContext.rollback() error_log(error) } } } However, running the above code will get me the following error CoreData`+[NSManagedObjectContextMultithreading_Violation_AllThatIsLeftToUsIsHonor]: If I modify the code by using NSFetchRequest directly. NSFetchRequest // Call from UI main thread func X() { let fetchRequest = NSFetchRequest<NSPlainNote>(entityName: "NSPlainNote") let coreDataStack = CoreDataStack.INSTANCE // backgroundContext created via persistentContainer.newBackgroundContext() let backgroundContext = coreDataStack.backgroundContext backgroundContext.perform { do { let nsPlainNotes = try fetchRequest.execute() } catch let error { backgroundContext.rollback() error_log(error) } } } Thing works fine. May I know, what's wrong with my NSAsynchronousFetchRequest version of code? This is my CoreDataStack.swift for reference purpose. CoreDataStack.swift import CoreData class CoreDataStack { static let INSTANCE = CoreDataStack() private init() { } private(set) lazy var persistentContainer: NSPersistentContainer = { let container = NSPersistentContainer(name: "wenote") container.loadPersistentStores(completionHandler: { (storeDescription, error) in if let error = error as NSError? { // This is a serious fatal error. We will just simply terminate the app, rather than using error_log. fatalError("Unresolved error \(error), \(error.userInfo)") } }) // So that when backgroundContext write to persistent store, container.viewContext will retrieve update from // persistent store. container.viewContext.automaticallyMergesChangesFromParent = true // TODO: Not sure these are required... // //container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy //container.viewContext.undoManager = nil //container.viewContext.shouldDeleteInaccessibleFaults = true return container }() private(set) lazy var backgroundContext: NSManagedObjectContext = { let backgroundContext = persistentContainer.newBackgroundContext() // Similar behavior as Android's Room OnConflictStrategy.REPLACE backgroundContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy // TODO: Not sure these are required... //backgroundContext.undoManager = nil return backgroundContext }() } Additional information Do note that, in NSAsynchronousFetchRequest example, even if backgroundContext.perform is not used. // Call from UI main thread func X() { let fetchRequest = NSFetchRequest<NSPlainNote>(entityName: "NSPlainNote") let asynchronousFetchRequest = NSAsynchronousFetchRequest(fetchRequest: fetchRequest) { asynchronousFetchResult in guard let result = asynchronousFetchResult.finalResult as? [NSPlainNote] else { return } } let coreDataStack = CoreDataStack.INSTANCE // backgroundContext created via persistentContainer.newBackgroundContext() let backgroundContext = coreDataStack.backgroundContext do { try backgroundContext.execute(asynchronousFetchRequest) } catch let error { backgroundContext.rollback() error_log(error) } } Same fatal error still occur. Please note that, this fatal error will only be triggered, by editing the schema with Arguments Passed On Launch -com.apple.CoreData.ConcurrencyDebug 1 I even try to execute some simple project from  https://github.com/abhishekbedi1432/Core-Data-Asynchronous-Fetching/tree/master which is using NSAsynchronousFetchRequest. If I do not enable -com.apple.CoreData.ConcurrencyDebug 1, the sample project from github able to perform asynchronous fetch without issue. However, once the -com.apple.CoreData.ConcurrencyDebug 1 is enabled, it will also be getting the same fatal error.
0
0
690
Dec ’21
Top status bar show/ hide animation is broken in iOS 15
I have the following top status bar hide/ show code snippet with animation. It works well under iOS 14.5 private var additionalHeight: CGFloat { if UIDevice.current.hasNotch { return 0 } else { return self.navigationController?.view.safeAreaInsets.top ?? 0 } } private var statusBarHidden: Bool = false { didSet { if statusBarHidden { self.navigationController?.additionalSafeAreaInsets.top = additionalHeight } else { self.navigationController?.additionalSafeAreaInsets.top = 0 } UIView.animate(withDuration: Constants.config_shortAnimTime) { () -> Void in self.setNeedsStatusBarAppearanceUpdate() } } } // https://medium.com/@badlands/unfortunately-this-also-applies-to-ipad-pro-which-have-non-zero-safeareainsets-e1aa0d002462 extension UIDevice { /// Returns 'true' if the current device has a notch var hasNotch: Bool { if #available(iOS 11.0, *) { // https://stackoverflow.com/a/57899013/72437 let keyWindow = UIWindow.key // Case 1: Portrait && top safe area inset >= 44 let case1 = !UIDevice.current.orientation.isLandscape && (keyWindow?.safeAreaInsets.top ?? 0) >= 44 // Case 2: Lanscape && left/right safe area inset > 0 let case2 = UIDevice.current.orientation.isLandscape && ((keyWindow?.safeAreaInsets.left ?? 0) > 0 || (keyWindow?.safeAreaInsets.right ?? 0) > 0) return case1 || case2 } else { // Fallback on earlier versions return false } } } iOS 14.5 However, when same code runs in iOS 15, the animation is broken. We use latest XCode 13.0 During hide, there is no more "slide up" hide animation. During show, it will try to "push down" the entire view controller. iOS 15 Does anyone has idea how to fix such animation in iOS 15, so that it behaves similar as iOS 14.5 ?
0
0
507
Oct ’21
Prevent scroll position from resetting when perform UITextView typing in UICollectionView
Currently, we try to place multiple UITextViews in UICollectionView. To ensure UICollectionView's cell height, will adjust based on the dynamic content of UITextView, this is what we have done. Disable scrolling in UITextView. Use .estimated(CGFloat(44)) for UICollectionViewCompositionalLayout Whenever there is text change, call collectionView.collectionViewLayout.invalidateLayout(). This is a critical step to ensure cell height will adjust accordingly. However, calling collectionView.collectionViewLayout.invalidateLayout() does come with a side effect. The current scroll position of UICollectionView will be reset, after calling collectionView.collectionViewLayout.invalidateLayout(). Does anyone know how can I Prevent unwanted auto scroll position resetting? UICollectionView will auto scroll to current cursor position, so that what is current being typed is visible to user? The code to demonstrate this problem is as follow - https://github.com/yccheok/checklist-demo Here's the code snippet, on what was happening as typing goes on func textViewDidChange(_ checklistCell: ChecklistCell) { // // Critical code to ensure cell will resize based on cell content. // // (But comes with a side effect which will reset scroll position.) self.collectionView.collectionViewLayout.invalidateLayout() // // Ensure our checklists data structure in sync with UI state. // guard let indexPath = collectionView.indexPath(for: checklistCell) else { return } let item = indexPath.item let text = checklistCell.textView.text self.checklists[item].text = text } Side Note Note, the closest solution we have came across is posted at https://medium.com/@georgetsifrikas/embedding-uitextview-inside-uitableviewcell-9a28794daf01 In UITableViewController, during text change, the author is using DispatchQueue.main.async { tableView?.beginUpdates() tableView?.endUpdates() } It works well. But, what is the equivalent solution for UICollectionView? We can't try out with self.collectionView.performBatchUpdates, as our solution is built around Diffable Data Source. I have tried DispatchQueue.main.async { self.collectionView.collectionViewLayout.invalidateLayout() } That doesn't solve the problem either. Thank you.
2
0
3.6k
Oct ’21
CoreData: Is it possible to have SQLite CASE WHEN...END logic in NSSortDescriptor?
Currently, I am porting several SQLite statement to CoreData. "SELECT id, \"order\" FROM plain_note WHERE archived = :archived AND trashed = :trashed " + "ORDER BY " + "CASE WHEN color_index = -1 THEN 12 + ABS(custom_color) ELSE " + "color_index END DESC, " + "\"order\" ASC" "SELECT id, \"order\" FROM plain_note WHERE archived = :archived AND trashed = :trashed " + "ORDER BY " + "title COLLATE NOCASE DESC, " + "CASE WHEN locked = 1 THEN NULL ELSE " + "CASE WHEN type = 0 THEN body ELSE searched_string END " + "END COLLATE NOCASE DESC, " + "\"order\" ASC" But, I am clueless on how I can make CoreData have the following CASE WHEN...END behavior, during sorting. CASE WHEN color_index = -1 THEN 12 + ABS(custom_color) ELSE color_index END DESC CASE WHEN locked = 1 THEN NULL ELSE CASE WHEN type = 0 THEN body ELSE searched_string END END COLLATE NOCASE DESC I was wondering, is there any possible technique I can use, so that NSSortDescriptor can have the similar behavior?
0
0
380
Sep ’21
“unsupported file format 'org.webmproject.webp'” while saving CGImage in webp format
Currently, we are using PHPickerViewController + CGImage for efficient memory usage consideration - https://christianselig.com/2020/09/phpickerviewcontroller-efficiently/ However, we are getting "unsupported file format 'org.webmproject.webp'" error, while trying to save CGImage in webp format. func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) { picker.dismiss(animated: true) guard !results.isEmpty else { return } for result in results { result.itemProvider.loadFileRepresentation(forTypeIdentifier: UTType.image.identifier) { (url, error) in guard let url = url else { return } let options: [CFString: Any] = [ kCGImageSourceCreateThumbnailFromImageAlways: true, kCGImageSourceCreateThumbnailWithTransform: true, kCGImageSourceShouldCacheImmediately: true, kCGImageSourceThumbnailMaxPixelSize: 512 ] guard let imageSource = CGImageSourceCreateWithURL(url as NSURL, nil) else { return } let image = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, options as CFDictionary) // // No issue in dealing with UTType.jpeg.identifier and UTType.png.identifier. // destUrl is type URL. // guard let destination = CGImageDestinationCreateWithURL(destUrl as CFURL, UTType.webP.identifier, 1, nil) else { return } CGImageDestinationAddImage(destination, image!, nil) CGImageDestinationFinalize(destination) } } We face no issue in saving CGImage in UTType.jpeg.identifier format and UTType.png.identifier format. May I know how can we save CGImage in webp format without issue? Thank you.
0
0
817
Aug ’21
Is it possible to make PHPickerViewController display multiple selection ordering number, instead of just an tick icon?
Currently, if we perform multiple selection on PHPickerViewController, a tick icon is being used to indicate selection. https://i.imgur.com/KCaSF9p.png However, such information doesn't convey information for the selection ordering. Is it every possible, to display the ordering number? This is an example from 3rd party library - https://github.com/mikaoj/BSImagePicker As you can see, the 3rd party library is using 1,2,3... to convey selection ordering information https://i.imgur.com/YoQVS4v.png Can we achieve the same behavior in PHPickerViewController? We prefer to use PHPickerViewController, because it doesn't need to request permission to access photo library. Thanks.
1
0
679
Aug ’21
performBatchUpdates completion handler is not called when there is section operation involved
So far, here's are the code snippets that almost work for NSFetchedResultsController + UICollectionView, based on the information provided https://developer.apple.com/videos/play/wwdc2018/225 (Starting at 36:50) https://stackoverflow.com/questions/38597804/how-to-order-moves-inserts-deletes-and-updates-in-a-uicollectionview-performb/53271562#53271562 Please note that, there are 2 [BlockOperation], as reloadItems and moveItem doesn't play well within single performBatchUpdates. Based on the workaround proposed in the video, we have to call reloadItems in a separate performBatchUpdates. We also do not follow 100% methods (Perform reloadItems typed performBatchUpdates first, followed by insert/ move/ delete typed performBatchUpdates) proposed in the video. This is because we notice that it doesn't work well even for simple case. Some strange behaviour including reloadItems will cause duplicated cell UI to be shown on screen. The "almost" work method we found are Perform performBatchUpdates for insert, move and delete At completion handler of performBatchUpdates, perform another performBatchUpdates for reloadItems NSFetchedResultsController + UICollectionView integration private var blockOperations: [BlockOperation] = [] // reloadItems and moveItem do not play well together. We are using the following workaround proposed at // https://developer.apple.com/videos/play/wwdc2018/225/ private var blockUpdateOperations: [BlockOperation] = [] extension DashboardViewController: NSFetchedResultsControllerDelegate { func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) { if type == NSFetchedResultsChangeType.insert { print(">> insert") blockOperations.append( BlockOperation(block: { [weak self] in if let self = self { self.collectionView!.insertItems(at: [newIndexPath!]) } }) ) } else if type == NSFetchedResultsChangeType.update { print(">> update") blockUpdateOperations.append( BlockOperation(block: { [weak self] in if let self = self, let indexPath = indexPath { self.collectionView.reloadItems(at: [indexPath]) } }) ) } else if type == NSFetchedResultsChangeType.move { print(">> move") blockOperations.append( BlockOperation(block: { [weak self] in if let self = self, let newIndexPath = newIndexPath, let indexPath = indexPath { self.collectionView.moveItem(at: indexPath, to: newIndexPath) } }) ) } else if type == NSFetchedResultsChangeType.delete { print(">> delete") blockOperations.append( BlockOperation(block: { [weak self] in if let self = self { self.collectionView!.deleteItems(at: [indexPath!]) } }) ) } } func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int, for type: NSFetchedResultsChangeType) { if type == NSFetchedResultsChangeType.insert { print(">> section insert") blockOperations.append( BlockOperation(block: { [weak self] in if let self = self { self.collectionView!.insertSections(IndexSet(integer: sectionIndex)) } }) ) } else if type == NSFetchedResultsChangeType.update { print(">> section update") blockOperations.append( BlockOperation(block: { [weak self] in if let self = self { self.collectionView!.reloadSections(IndexSet(integer: sectionIndex)) } }) ) } else if type == NSFetchedResultsChangeType.delete { print(">> section delete") blockOperations.append( BlockOperation(block: { [weak self] in if let self = self { self.collectionView!.deleteSections(IndexSet(integer: sectionIndex)) } }) ) } } func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) { if blockOperations.isEmpty { performBatchUpdatesForUpdateOperations() } else { collectionView.performBatchUpdates({ [weak self] () -> Void in guard let self = self else { return } for operation: BlockOperation in self.blockOperations { operation.start() } self.blockOperations.removeAll(keepingCapacity: false) }, completion: { [weak self] (finished) -> Void in print("blockOperations completed") guard let self = self else { return } self.performBatchUpdatesForUpdateOperations() }) } } private func performBatchUpdatesForUpdateOperations() { if blockUpdateOperations.isEmpty { return } collectionView.performBatchUpdates({ [weak self] () -> Void in guard let self = self else { return } for operation: BlockOperation in self.blockUpdateOperations { operation.start() } self.blockUpdateOperations.removeAll(keepingCapacity: false) }, completion: { [weak self] (finished) -> Void in print("blockUpdateOperations completed") guard let self = self else { return } }) } } The above way, works "almost" well when no "section" operations involved. If there is item moved operation between different section, the following logging will be printed blockOperations completed >> move blockOperations completed >> move blockOperations completed However, if there are item being moved and section being added/ removed, the following logging will be printed >> section delete >> move >> section insert >> move This means the completion handler block is not executed! Does anyone know why it is so, and how I can workaround with this issue? Thanks.
0
0
1.1k
Jul ’21
May I know how can I use SF Symbols beta to create custom icon?
I am using "checkmark.circle.fill" I wish to have a blue filled circle with the checkmark being solid black. For the blue filled circle, I can choose the tinted color as blue. But, the default SF Symbols "checkmark.circle.fill", its checkmark is transparent. It looks as follow So, I try to use "SF Symbols beta", to create custom icon. During editing, the thing seems like what I want Blue filled circle Solid black color for checkmark Then, I use "Export Symbol...", using Template Version 2.0 (XCode cannot recognise Template Version 3.0) It seems like the checkmark fall back to transparent color. When I import it to XCode It seems like the "solid black color" on the checkmark is gone. When I use this custom icon in my app, it gave same result as "checkmark.circle.fill" (the checkmark still remain as transparent) Doesn't anyone know how to resolve this issue? Thanks.
1
0
3.2k
Jul ’21
Why creating index in CoreData will end up duplicated index (with different name) in SQLite file?
I was wondering did anyone of you come across this strange situation? I tried to index a property in entity. For instance, for entity named NSPlainNote, I try to create an index named index_plain_note_label, on property label. This is how it looks like. However, if I inspect the content of the generated SQLite file. It seems that 2 same indices with different name are created. CREATE INDEX Z_NSPlainNote_index_plain_note_label ON ZNSPLAINNOTE (ZLABEL COLLATE BINARY ASC) CREATE INDEX Z_NSPlainNote_label ON ZNSPLAINNOTE (ZLABEL COLLATE BINARY ASC) If we observe carefully, such duplication also happen in all other index with 1 property like NSPlainNote's order NSPlainNote's sticky NSTabInfo's order Such duplication does not happen on index with 2 properties, or index with unique constraint. May I know why it is so? Is there any step which I have done incorrectly?
0
0
419
Jul ’21
Is NSAsynchronousFetchRequest suitable for production app?
NSAsynchronousFetchRequest seems like an answer to read large amount of data from CoreData, without blocking main thread. But, it is lacking some key features, provided by NSFetchedResultsController. The key features are :- In NSFetchedResultsControllerDelegate didChange and controllerDidChangeContent, we automatically receive a complete change information of persistence store. This enables us to implement the animation of add/delete/move/modify in collection view. Always listen to DB changes. Whenever there is changes being written into the persistence store, NSFetchedResultsControllerDelegate didChange and controllerDidChangeContent will be triggered automatically. This enables us to ensure our UI is in sync with DB. But, NSAsynchronousFetchRequest doesn't come with NSAsynchronousFetchedResultsController :( I was wondering, if you were using NSAsynchronousFetchRequest, how do you implement Animation changes on collection view? Always listen to DB change? My initial thought for animation changes on collection view, it seems we can utilise UICollectionViewDiffableDataSource. But, I notice it might be highly memory inefficient to do so. We need to keep ALL NSManagedObject in memory, fire all faults during comparison. It looks like we will run out of memory, if there are many rows. May I know, how do you achieve the following features, if you ever apply NSAsynchronousFetchRequest in production app? Animation changes on collection view? Always listen to DB change? Thanks.
1
0
627
Jun ’21