I am working on chatting app in iOS using xmpp and ejabberd . I am not able to remove single message.
Is this correct method - (void)removeResources:(NSSet *)value to remove chat? And what parameter I need to remove chat?
Or do I need to remove entry from core data? On Quick Blox I found this method:
NSSet *mesagesIDs = [NSSet setWithObjects:#"54fdbb69535c12c2e407c672", #"54fdbb69535c12c2e407c673", nil];
[QBRequest deleteMessagesWithIDs:mesagesIDs
How to use this in my project without quickblox?
If you have XMPPMessageArchiving_Message_CoreDataObject. i think this object is used to display data in UITableView so you can direct removed that object from core data using below code. Here i am showing to delete loop of messages.
NSManagedObjectContext *moc = [self managedObjectContext];
for (XMPPMessageArchiving_Message_CoreDataObject *message in messages)
{
[moc deleteObject:message];
}
Hope this help you.
Related
I have an app structured as follows
iOS App Writes data to Core Data which has a persistent store stored in a shared app group.
The Watch Kit extension is able to read data from Core Data that was written by the iOS app.
The issue I am having is if my iOS app writes data while my watch kit app is open I am not getting updates because the object context is not syncing with the data on the disk.
Is there a way that since my watch kit extension is only reading data to be able to refresh the context and force it to load again from the data on the disk?
My working solution was using MMWormhole to send notification (NSManagedObjectContextDidSaveNotification) from iPhone app to my watch app. In the watch app's controller i used mergeChangesFromContextDidSaveNotification: method of NSManagedObjectContext.
// in iPhone app's notification handler
MMWormhole *wormhole = [[MMWormhole alloc] initWithApplicationGroupIdentifier:#"your.group.container.identifier" optionalDirectory:nil];
[wormhole passMessageObject:notification identifier:#"your notification identifier"];
// in WKInterfaceController's awakeWithContext: method
MMWormhole *wormhole = [[MMWormhole alloc] initWithApplicationGroupIdentifier:#"your.group.container.identifier" optionalDirectory:nil];
[wormhole listenForMessageWithIdentifier:#"your notification identifier" listener:^(id messageObject) {
[self.managedObjectContext mergeChangesFromContextDidSaveNotification:messageObject];
}];
Then NSFetchedResultsController did all other work with UI updates.
You must implement initWithCoder: and encodeWithCoder: methods from NSCoding protocol for your NSManagedObject subclasses because MMWormhole uses NSKeyedArchiver as a serialization medium.
- (id)initWithCoder:(NSCoder *)decoder {
NSManagedObjectContext *context = ... // use your NSManagedObjectContext
NSPersistentStoreCoordinator *coordinator = ...; //use your NSPersistentStoreCoordinator
NSURL *url = (NSURL *)[decoder decodeObjectForKey:#"URIRepresentation"];
NSManagedObjectID *managedObjectID = [coordinator managedObjectIDForURIRepresentation:url];
self = [context existingObjectWithID:managedObjectID error:nil];
return self;
}
- (void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:[[self objectID] URIRepresentation] forKey:#"URIRepresentation"];
}
I ran into the same issue. I used - (void)refreshObject:(NSManagedObject *)object mergeChanges:(BOOL)flag in the NSManagedObjectContext to get the latest data for the managed object.
Ran into similar issues. Despite creating a shared Fetched Results Controller in the App Group observing Managed Object Context changes and refreshing Managed Object Context were not feasible.
Managed Object Contexts cache a certain level of the object graph for retrieval without reading from the actual SQLite store on the disk. The only potential way to actually get live sync between the two would be sending messages across iOS app to Extension when the MOC changes and destroying/rebuilding the Core Data stack from the disk every single time, not a great solution at all.
I believe the use case for live sync between iOS and Extension at initial launch isn't a necessity. Hopefully we get a more deliberate solution to this problem in a future release.
I have an app which asynchronously downloads a JSON file and then it should insert those objects within Core Data for persistent storage. Regarding the insert, is it a good idea to do it from the main thread? What if there are thousands of objects? Should I do the inserts on a different thread? Could you provide me with some snippets regarding this matter? Regarding the fetching of the objects after I've saved them, should I also use a different thread?
My code for inserting into Core Data is:
- (void) insertObjects:(NSArray*)objects ofEntity:(NSString *)entityName
{
NSString *key;
NSManagedObject *managedObject;
NSError *error;
for(NSDictionary *dict in objects){
managedObject = [NSEntityDescription insertNewObjectForEntityForName:entityName inManagedObjectContext:_managedObjectContext];
for(key in dict){
[managedObject setValue:dict[key] forKey:key];
}
}
[_managedObjectContext save:&error];
}
PS: The objects are of the same entity. The project runs on iOS 7.0 or higher.
Since I can't comment yet..
What iOS Versions do you plan to support? If 5 and higher, this might help Concurrency stack
Summary of the link:
you create a context of private concurreny type to access your physical data
based on this you create a context of main concurreny type
on top of this you use private concurrency type stores again.
Don't forget so save in every store, otherwise, the data seems to be saved while the app is running, but after restart it is lost.
And yes, you want to do it an extra thread, since it would otherwise block the UI if there are to many items.
I'm using Magical Record 2.1 to handle the data persistence in my app. If I create a new entity, set some it's attributes and save, it works fine. However, later, if I fetch that entity, update it's attributes and save, subsequent fetches have the new data until I terminate the app and restart. During the new app session the old data reappears.
This is how I create a new entity:
self.localContext = [NSManagedObjectContext MR_defaultContext];
self.theNewListing = [Listing MR_createInContext:self.localContext];
I'm using MRDefaultContext having read this blog post: http://saulmora.com/2013/09/15/why-contextforcurrentthread-doesn-t-work-in-magicalrecord/
In this case my main attribute is a dictionary, and I set it like this:
NSMutableDictionary *tempDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:#"A description", #"slFieldDescription", etc, etc, nil];
self.theNewListing.dataDictionary = tempDictionary;
This is how I save it:
[self.presentingViewController dismissViewControllerAnimated:YES completion:^(void) {
[self.localContext MR_saveToPersistentStoreWithCompletion:^(BOOL success, NSError *error){
if(!success) {
NSLog(#"%#", error);
}
else {
[self.thePresentingVC refreshCollectionViews:nil];
}
}];
}];
I display my data in a collection view, and at this point everything looks fine. If I terminate and restart the data is still there.
If I fetch the entity again and update the attributes like this:
NSMutableDictionary *newTempDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:#"A new description", #"slFieldDescription", etc, etc, nil];
self.theNewListing.dataDictionary = newTempDictionary;
Then save using the same save code as above, and then update my collection view using the code below, all looks good.
self.listingsArray = [[NSMutableArray alloc] initWithArray:[Listing MR_findAllSortedBy:#"dateListed" ascending:NO]];
[self.mainCollectionView reloadData];
That is, until I quit the app and restart.
If you're wondering, I'm using FTASync, and this only supports MR 2.1, which is why I haven't upgraded to the latest version.
Thanks!
Not sure about MR, nor why you would need it. If that framework can give you the main context, just call the native Core Data save.
[context save:nil];
Cracked it!!
I noticed that my other attributes were saving, just not this one (this one holds all the data that is presented in the UI) and this led me on another line of investigation.
So, it seems that I needed to be working with immutable dictionaries to store this data as explained here:
Core Data saving problem: can't update transformable attribute (NSArray)
I have defined a Core Data for my project and implemented an ENtity:attribute called isRealEntry.
#interface FTRecord : NSManagedObject
#property (nonatomic) NSTimeInterval lastUpdated;
#property (nonatomic) BOOL isRealEntry;
#end
Now when I save the context (NSManagedObjectContext *context;)
NSError *error = nil;
BOOL successful = [context save:&error];
I would like to save only those entities that have a true isRealEntry, otherwise the entry shall be ignored or undone.
How can I achieve this?
Update:
At first I found Martin's solution very promising. However I get a very nasty side effect when I save my data upon entering background:
- (void)applicationDidEnterBackground:(UIApplication *)application
{
[[FTRecordStore sharedStore] saveChanges];
}
When I resume the app, all the previous deleted records aren't gone for real but flagged to be deleted. The array still seems to have all of them (real or unreal in my case). The cells go completely nuts and show empty for all records.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
FTRecord *record = [[[FTRecordStore sharedStore] getAllRecords] objectAtIndex:[indexPath row]];
FTRecordCellView *cell = [tableView dequeueReusableCellWithIdentifier:#"FTRecordCellView"];
[[cell notesLabel] setText:[record notes]];
return cell;
}
I am not sure how to solve this. My Store is a singleton. getAllRecords determines above the content for each cell. Hence I need to have the same value for getAllRecords as also in the tableView, or it would crash.
The other suggested solution with two sources one in memory and in db seems also not to be possible, how do I feed one TableView with two sources?
Update 2:
I had an embarassing oversight. Deleting the record from context is not enough. I also had to delete it from the array.
[allRecords removeObjectIdenticalTo:record];
Therefore I take it back. Martin's solution works perfect. However I am still curious to know if a UITableView can indeed be driven from two sources (db/memory) as suggested in teh other solution. Thanks
I've had to do something similar to this before and the way I approached it was to have a seperate managed object context for items that I was going to persist, and another for items that were staying in memory only.
I went about it by having a seperate persistent store cordinator as well as a separate managed object context that is in memory only, so when items are saved into it, they don't get persisted to the database with what you described as real items.
You can create an in memeory persistent store coordinator like this:
inMemoryPersistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
[inMemoryPersistentStoreCoordinator addPersistentStoreWithType:NSInMemoryStoreType configuration: nil URL: nil options: nil error: &error];
If you want to change non real items into real items, you can copy them into the other managed object context which will persist the items to the database when it's saved.
The obvious issue here is that searching is done on a single managed object context so if you hoped to search through persisted and in memory objects, then you would need to do something more along the lines of what Arkadiusz suggested in his answer.
Saving a managed object contexts saves all changes make to that context. You cannot
exclude some objects from the save operation.
To undo all changes to the "unreal" objects, you could implement the willSave
method of the NSManagedObject subclass:
- (void)willSave
{
if (![self.isRealEntry boolValue]) {
if (self.isInserted) {
// Object was inserted, remove it again:
[self.managedObjectContext deleteObject:self];
} else if (self.isUpdated) {
// Object was modified, undo all changes:
[self.managedObjectContext refreshObject:self mergeChanges:NO];
}
}
}
(I never did this in a real project, but I built a small test app and
it seems to work.)
I don't believe there is a built in way to do this. I believe you would either have to delete them before saving or write cleanup code to find and delete them later.
In the below example code I am passing amanagedContext object via a property of the view controller this selector lives in. In this case this property is currentPetCoreDataObject.
Does someone have a simple project, not necessarily iOS project, that has a one to many relationship in it using the Core Data framework? A simple command-line app would do. All the examples with relationships that I can find are one to one.
I don't know how to use the generated selector in the xCode Generated entity class and couldn't find any examples:
- (void)insertObject:(Feeding *)value inPetFeedRelationAtIndex:(NSUInteger)idx;
The following code appears to work but when checking the count, it doesn't appear to be saving. What am I missing?
I am new to Core Data and have not yet successfully used a relation.
if (!self.nsMutableOrderedSetFeed)
{
NSLog(#"current feed count:%d", self.currentPetCoreDataObject.PetFeedRelation.count);
[self.addedFeedObject setBrand:self.txtBrand.text];
[self.addedFeedObject setFood:self.txtType.text];
[self.addedFeedObject setParentPetRelation:self.currentPetCoreDataObject];
[self.addedFeedObject addPetFeedRelationObject:self.addedFeedObject];
//[self.currentPetCoreDataObject insertObject:self.addedFeedObject inPetFeedRelationAtIndex:[self.currentPetCoreDataObject.PetFeedRelation i];
[self.currentPetCoreDataObject setPetFeedRelation:[self.nsMutableOrderedSetFeed initWithObject:self.addedFeedObject]];
}
NSError *error;
if (![self.managedObjectContext save:&error])
NSLog(#"Failed to add new Pet profile with error: %#", [error domain]);
[self dismissViewControllerAnimated:NO completion:nil];