swift request coredata and delete - swift

i would like to request all my core data where the "mhd" field >= the date of today. this code works fine:
func DatenAbrufen() {
let calendar = NSCalendar.currentCalendar()
let AktuellesDatum = calendar.startOfDayForDate(NSDate())
let fetchRequest = NSFetchRequest(entityName: "LM_ITEMS")
fetchRequest.predicate = NSPredicate(format: "mhd >= %#", AktuellesDatum)
if let fetchResults = managedObjectContext!.executeFetchRequest(fetchRequest, error: nil) as? [LM_ITEMS] {
lebensmittel = fetchResults
}
}
how can i delete in this query all other data, where "mhd" is not >= date of today?

If you need to support iOS 8.x, or OS X Yosemite, or older, you'll need to fetch each object and then delete it. Write another predicate that is the opposite of the one you have. Execute that fetch request. Then iterate over the found objects and send each one a deleteObject. Save your managed object context. This can take quite a while, if you're deleting lots of objects.
For iOS 9 and El Capitan, you can use NSBatchDeleteRequest, described in WWDC 2015 session 220. For large numbers of deleted objects, NSBatchDeleteRequest is much faster. You're not loading each object into memory just to delete it. You also bypass some validation rules, and must refresh your MOC for it to see changes–which might be undesired consequences, depending on your usage.

Related

func removeFilterPredicate(_ predicate: MPMediaPredicate) not working consistently

I am experiencing an inconsistent issue when trying func removeFilterPredicate(_ predicate: MPMediaPredicate) however I never have an issue when trying func addFilterPredicate(_ predicate: MPMediaPredicate)
When I test my app and add the predicate it works every time without fail. When I try to remove the predicate usually it works, but sometimes it does not.
The behavior I expect is to remove the predicate and then a random song that does not match the previous predicate to play
What is actually sometimes happening is after I remove the predicate and skip to next song more songs from the previous predicate still play
I have found if I want to guarantee it to fail I can do so by adding the predicate to only play songs from a specific Artist and then rapidly skip a few songs and then try to remove the predicate.
The way I add the predicate is
func getSongsWithCurrentArtistFor(item: MPMediaItem) -> MPMediaQuery {
let artistPredicate = MPMediaPropertyPredicate(value: item.artist, forProperty: MPMediaItemPropertyArtist, comparisonType: .contains)
let query = MPMediaQuery()
query.addFilterPredicate(artistPredicate)
return query
}
let lockArtist = MediaManager.shared.getSongsWithCurrentArtistFor(item: nowPlaying)
if var items = lockArtist.items {
items.shuffle()
let descriptor = MPMusicPlayerMediaItemQueueDescriptor(itemCollection: MPMediaItemCollection(items: items))
self.mediaPlayer.prepend(descriptor)
}
Which again NEVER fails
To remove the predicate:
func removeArtistLockFor(item: MPMediaItem) -> MPMediaQuery {
let artistPredicate = MPMediaPropertyPredicate(value: item.artist, forProperty: MPMediaItemPropertyArtist)
let query = MPMediaQuery()
query.removeFilterPredicate(artistPredicate)
return query
}
let unlockArtist = MediaManager.shared.removeArtistLockFor(item: nowPlaying)
if var items = unlockArtist.items?.filter({ (item) -> Bool in
return item.mediaType.rawValue <= MPMediaType.anyAudio.rawValue
}) {
items.shuffle()
let descriptor = MPMusicPlayerMediaItemQueueDescriptor(itemCollection: MPMediaItemCollection(items: self.newSongs.shuffled()))
self.mediaPlayer.prepend(descriptor)
}
I am wondering if A) There is an issue with the way I am removing MPMediaPropertyPredicate, B) I need some sort of added method to fix the edge case of rapidly changing song, or C) both.
I know I have previously posted about issues with MPMediaPlayer .. specifically aboutfunc prepend(_ descriptor: MPMusicPlayerQueueDescriptor) but those issues were resolved in ios13. This is a new issue...and the fact that adding the predicate ALWAYS working makes me think this is more of a mistake on my part and not Apple's issue...?
The lines in your removeArtistLockFor function
let query = MPMediaQuery()
query.removeFilterPredicate(artistPredicate)
...appears to be creating a new instance of MPMediaQuery so unless it behaves like a singleton (which from the documentation doesn't appear to be the case), there will be nothing to remove at this point.
Should you be holding on to a reference to the query from when you add the predicate and pass it in to the remove function so you can then do
passedQuery.removeFilterPredicate(artistPredicate)

How to Fetch Records from CloudKit Not in My Local Cache

I have an app that uses CloudKit for sync and I maintain a local cache of records. I have run into a sync scenario that I can't figure out.
I'm using the Public database and when my app is opened, I want to be able to go get all the updated records that my app missed while it was closed, or on a device where the app was just installed.
I can get the updated records by creating a NSPredicate to compare the modificationDate like this:
let predicate = NSPredicate(format: "modificationDate > %#", syncTimestamp as CVarArg)
let query = CKQuery(recordType: recordType, predicate: predicate)
But the part I can't figure out is how to get only the records that have been added to, or removed from, the CloudKit server.
Does anyone know how to do this? I know Apple provides a way for this in the Private database but I'm using the Public one here.
The only thing I can think of so far is to query all the reocrds of a certain recordType, collect all their recordNames and compare to my local cache. But it'd be nice to have smarter way than just pull large amounts of data and comparing huge arrays of recordNames.
CKQuerySubscription(recordType: myRecordType, predicate: predicate, options: [.firesOnRecordCreation, .firesOnRecordDeletion]) works perfectly on public DB.
Here's a code snippet (saving subscription is done with RxCloudKit, but this is beyond the point) -
let predicate = NSPredicate(format: "TRUEPREDICATE")
// the options are different from what you need, just showcasing the possibilities:
let subscription = CKQuerySubscription(recordType: recordTypeTest, predicate: predicate, options: [.firesOnRecordCreation, .firesOnRecordUpdate, .firesOnRecordDeletion, .firesOnce])
let info = CKNotificationInfo()
info.alertLocalizationKey = "NEW_PARTY_ALERT_KEY"
info.soundName = "NewAlert.aiff"
info.shouldBadge = true
subscription.notificationInfo = info
self.publicDB.rx.save(subscription: subscription).subscribe { event in
switch event {
case .success(let subscription):
print("subscription: ", subscription)
case .error(let error):
print("Error: ", error)
default:
break
}
}.disposed(by: self.disposeBag)

Better approach to querying sqlite database in swift

I'm working on a word game and have bundled a complete list of english words using a sqlite database. I'm trying to find the best way to search the database for a given string to determine if it's a word.
At this point I can get the whole database out into an array:
func fetchWords() {
if let managedObjectContext = (UIApplication.shared.delegate as? AppDelegate)?.managedObjectContext {
let wordsFetch = NSFetchRequest<NSFetchRequestResult>(entityName: "EnglishWord")
do {
englishWords = try managedObjectContext.fetch(wordsFetch) as! [EnglishWord]
print(englishWords[123323].word)
//Prints "injustices"
} catch {
//error handling
}
}
}
Now. What I really want to do is pass in a given string and see if it exists as a word in my database. I have a clunky solution with predicates, e.g:
func fetchWordsToArray() {
if let managedObjectContext = (UIApplication.shared.delegate as? AppDelegate)?.managedObjectContext {
let wordsFetch = NSFetchRequest<NSFetchRequestResult>(entityName: "EnglishWord")
let searchWord = ["dastardly"]
let searchPredicate = NSPredicate(format: "word = %#", argumentArray: searchWord)
do {
englishWords = try managedObjectContext.fetch(wordsFetch) as! [EnglishWord]
let resultFilteredByPredicate = (englishWords as NSArray).filtered(using: predicate)
print(resultFilteredByPredicate)
} catch {
//error handling
}
}
}
But in order to use the filtered function I have to convert to an NSArray which means I can't work with the results directly (e.g. get resultFilteredByPredicate.word).
Also it feels like I'm probably going about this all the wrong way. Since everything has to go into an array first, I must be losing a lot of the value of using an sqlite database in the first place.
Any suggested approaches for better working with the database?
Many thanks in advance for any help!
To make the database do the filtering (which could then be optimized automatically with an index), put a predicate on the original fetch request:
let formatRequest : NSFetchRequest<Word> = Word.fetchRequest()
fetchRequest.predicate = NSPredicate(format: "word == %#", searchWord)
let fetchedResults = try context.fetch(fetchRequest) as! [Word]
But Core Data is a framework to manage your objects.
If you decide that your words are not objects but just values, you could replace Core Data with some other library that does SQL directly, and execute an SQL query instead:
SELECT * FROM EnglishWord WHERE word = ?

Fetching a one to many relationship using Core Data

iam a swift beginner, i wanna code a little app for me and i have a problem with it. My app has three entities (Templates, Records and Positions), here you can see:
Datamodel
At one part of the app i can add new Records and for that Record i add some Positions (xpos and ypos).
At a part I have a tableview were i list my Records. Now i wanna click one Record in the table and i want to get all Position-Attributes linked with the particular selected Record.
With that code i can get all xpos-Positions but how can i get a single xpos? :)
guard let moc = self.managedContext else {
return
}
let fetchRequest: NSFetchRequest<Records> = Records.fetchRequest()
do {
let searchResults = try moc.fetch(fetchRequest)
let xpos = searchResults[0].positions?.mutableArrayValue(forKey: "xpos")
print(xpos)
} catch {
print("Error with request: \(error)")
}
You want to look into using NSPredicate. NSPredicate basically lets you define the conditions which the record needs to meet to be included in the results. Think of it as a filter if you will.
fetchRequest.predicate = NSPredicate(format: "uniqueID = %#", arugments:...)

How fetch relationship from CoreData in swift?

I think this is simple but i can't find answer for me. I have two tables. Contacts and messages. Like this:
And my relationships are in contacts
And in Messages
enter image description here
I need take SQL: SELECT contacts.nickName, messages.id, messages.message FROM messages JOIN contacts.ccNumber = messages.senderCcNumber
My code for now getting a all data from Messages but i don't know how to join table Contacts to this fetch.
let appDel: AppDelegate = (UIApplication.sharedApplication().delegate as! AppDelegate)
let context: NSManagedObjectContext = appDel.managedObjectContext
let request: NSFetchRequest = NSFetchRequest(entityName: "Messages")
request.returnsObjectsAsFaults = false
request.predicate = NSPredicate(format: "senderCcNumber = %#", argumentArray: ["\(senderID)"] )
request.sortDescriptors = [NSSortDescriptor(key: "added", ascending: true)]
do { resultsMessagesList = try context.executeFetchRequest(request) } catch {}
print(resultsMessagesList)
return resultsMessagesList
Can someone give me a hint ?
CoreData is not a database. You don't need to join any tables (there are no tables).
You shouldn't be storing any foreign keys either.
Once you have a message you can get the contacts array by using message.contacts. You don't need to execute any fetch requests to do this. (Other than to get the message in the first place).
Also, your entities should have singular names (Contact not Contacts).
If your messages have a sender and a receiver then create two relationships one called sender and the other called receiver and connect them to the Contact entity.
I'd recommend investing in a CoreData basics book. Or there are some very good tutorials online. You would be saving yourself time in learning to use CoreData properly.