Are there Core Data call back methods? - core-data

I am wondering if there is any special way to take action when something happens in a core data entity.
Here what I mean in the present case. I have a file name stored as an attribute in a core data entity.
As the app is running, it can happen that the item with this file name is removed from core data.
In that case what I want to happen is that the file gets removed from the file system.
And this is my question:
Do I need to write my own code to perform this removal?
Or is there a way, that I could use, so a removal procedure would be fired automatically when the item is removed from core data?
In other words, is there a call back method like:
-(void) objectWillBeRemoved:((NSManagedObject*))object
or:
-(void) objectHasBeenRemoved:((NSManagedObject*))object
Thanks for any relevant tip.

Check out NSManagedObjectContextObjectsDidChangeNotification.
You can read about it in NSManagedObjectContext Class Reference.

NSManagedObject#willSave and NSManagedObject#didSave should do what you want. See apple documentation

Related

Cocoa Bindings not updating NSTextField value

I have two windows, one is a table view to display content. One is a window for inputting content.
I have an NSTextField binded to a property in my app delegate. When I change a value in the text field, the app delegate property will change. However, if I go the other way and programmatically change the property's binded key, the value of the text field does not update. However, it does in the table view.
What is going wrong here? How can I update text field?
EDIT:
I tried all 3 of these with the same result
[_addEntry setValue:#"Chet" forKey:#"payee"];
[_addEntry setPayee:#"chet"];
_addEntry.payee = #"chet";
EDIT:
Here's a simple example to elaborate on my point
https://dl.dropboxusercontent.com/u/48014761/test.zip
the label and the textfield are bound to the "str" property. It is initially null. press log to see that in the console. press change str button to change the string. Log to verify. Note that the label and the textfield do not update!
EDIT:
"What am I trying to accomplish?"
Here's the project I am working with:
https://dl.dropboxusercontent.com/u/48014761/Write-Offs.zip
I am trying to use Cocoa Bindings as much as possible. I have a table with a bunch of data. However, each entry is going to have an array of images associated with it. Thus, when I add a new entry, I need to open up a new window so I can set the properties of that entry (rather than through the table) along with upload some images.
I am not sure I am implementing the addEntryWindow correctly. It seems like I should create and destroy the window each time I open and close it. This doesn't appear to be happening.
Also, [[self addEntry] setDate:[NSDate date]]; doesn't seem to fix the problem for me.
Thanks
Chet
How are you programmatically changing the field? Are you using KVO? Is the field inside of a NSManagedObject instance?
Bindings work through KVO. Core Data disables some aspects of KVO for its own internal uses and you might be tripping over one of those.
Update your question with the code sample and lets see what is going on.
Update
Both windows don't necessarily need to be in the same xib but they do need to be talking to the same instances. Ideally they should both be talking to the same instance of NSManagedObject and therefore talking to the same NSManagedObjectContext.
Who is the owner of each window?
Is the owner the same?
If not, is a new Core Data stack being created?
Update
In your test, I was able to correct it by how you were editing the property
- (IBAction)press:(id)sender {
[self setStr:#"this"];
}
You were accessing the iVar directly instead of the property. When you access the iVar directly KVO does not fire.
In addition, in your xib files you were accessing self.str which is unnecessary. It should be just str.
Are you doing any direct property access in your actual project?
Update
You can do a get accessor and then a set accessor:
[[self addEntry] setPayee:xxx];
Based on the variables you are using I wonder what you are trying to accomplish. Can you post the exact code of the programmatic change you are trying to enact?

is there a way to see which objects in a managedobjectcontext have not yet been added to the persistent store?

is there a simple and efficient/fast way to query a managedobjectcontext to get an array of all the managedobjects in the context that have not yet been added to the persistent store?
i ask this because i would like to be able to save nsmanagedobjects that have been added to the MOC only if they conform to certain criteria. basically i want to be able to do this so that if some unexpected event happened before my managed object attributes were properly populated, i can catch this fact and purge the object(s) before saving the context. given the complexity of the navigation possible in the app, i'd like to have a look at the data to be sure they are good before i save.
i suppose i could also do this with some kind of validation rule and a flag field that doesn't get set until i am sure the user has added all the data to the record, but i don't yet know how to implement this...
any help much appreciated.
The insertedObjects method of NSManagedObjectContext
returns the set of objects that have been inserted into the context but not yet saved in a persistent store.

Core Data - NSFetchedResultsController bug

It seems controllerDidChangeContent: is being called as soon as I create a new managed object in my context. The documentation seems to suggest this method is called only once you save: the context.
This "bug" if it is one, is causing my application to crash because as part of my table view cell, I need to load other managed objects that don't exist at the time of creating the main managed object.
Someone seems to have spotted this too, please check out the following link and I would love to hear your opinions on this: http://openradar.appspot.com/10207615
More information
Although the link I added to this post showcases an example using two NSManagedObjectContext, my application is using one context, but the controllerDidChangeContent: is being messaged none the less as soon as an object is created in the one and only context, and controllerDidChangeContent: is being called a second time when I save: this context. It is to my understanding that this method should only be messaged when the context is saved.
The solution is to avoid dealing with more than one managedObjectContext. If your cell needs to load other managed objects, it should still use the same managed object context as the main managed object.
I have yet to see a use case where it is absolutely unavoidable to use more than one managed object context referring to the same model active at the same time.

Restore one fetched entity out of many -- Core Data

This question covncerns my lack of understanding of how to use the core data undo manager and how to restore a NSManagedObject to its state before editing was done.
I am just learning my way around Core Data. I have my NSManagedObject classes set up with their dynamic accessors. I perform a fetch that returns several NSManagedObject entity results. Content from each of these entity results (first name, last name) get put into a table view, and then the user picks one out of the table for detailed view and then editing.
The detail view controller receives a pointer to the selected NSManagedObject entity. As the user edits the fields, the corresponding property value in the NSManagedObject entity is updated. This seemed like the cleanest way to manage these changes.
Now, rather than committing the changes using save, I want to provide a cancel-editing feature that rolls back to what is in the data base for that entity. I really only want to restore the one entity and not perform the entire refetch.
I tried rollback and I tried NSUndoManager (with beginUndoGrouping and endUndoGrouping), and that is not working. I don't think I understand what rollback is really supposed to do.
But in any case, I still want to restore the property values in just that single entity (taking the lazy approach to only fetch what is needed, which is the one entity) so that my detail view controller can refill its view with the correct information. Right now it is using the NSManagedObject entity values, which contain the edited values, which were cancelled.
I suppose I could just start the edit process by creating a copy of the NSManagedObject. If the cancel-editing button is pressed, I could copy it back into the original. (I might even be able to just replace the original with the copy by moving the pointer. But since the pointer has actually been passed through several objects, I'm not sure how to manage the retain number on the copy.)
Does anyone have any other suggestions?
Thanks
Using rollback should accomplish what you want and I'm not sure what it doesn't. It is probably an implementation detail error.
You can find the specific managed object/s that were updated but not yet saved by calling the context's updatedObjects.

Help to restructure my Doc/View more correctly

Edited by OP.
My program is in need of a lot of cleanup and restructuring.
In another post I asked about leaving the MFC DocView framework and going to the WinProc & Message Loop way (what is that called for short?). Well at present I am thinking that I should clean up what I have in Doc View and perhaps later convert to non-MFC it that even makes sense. My Document class currently has almost nothing useful in it.
I think a place to start is the InitInstance() function (posted below).
In this part:
POSITION pos=pDocTemplate->GetFirstDocPosition();
CLCWDoc *pDoc=(CLCWDoc *)pDocTemplate->GetNextDoc(pos);
ASSERT_VALID(pDoc);
POSITION vpos=pDoc->GetFirstViewPosition();
CChildView *pCV=(CChildView *)pDoc->GetNextView(vpos);
This seem strange to me. I only have one doc and one view. I feel like I am going about it backwards with GetNextDoc() and GetNextView(). To try to use a silly analogy; it's like I have a book in my hand but I have to look up in it's index to find out what page the Title of the book is on. I'm tired of feeling embarrassed about my code. I either need correction or reassurance, or both. :)
Also, all the miscellaneous items are in no particular order. I would like to rearrange them into an order that may be more standard, structured or straightforward.
ALL suggestions welcome!
BOOL CLCWApp::InitInstance()
{
InitCommonControls();
if(!AfxOleInit())
return FALSE;
// Initialize the Toolbar dll. (Toolbar code by Nikolay Denisov.)
InitGuiLibDLL(); // NOTE: insert GuiLib.dll into the resource chain
SetRegistryKey(_T("Real Name Removed"));
// Register document templates
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CLCWDoc),
RUNTIME_CLASS(CMainFrame),
RUNTIME_CLASS(CChildView));
AddDocTemplate(pDocTemplate);
// Parse command line for standard shell commands, DDE, file open
CCmdLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
// Dispatch commands specified on the command line
// The window frame appears on the screen in here.
if (!ProcessShellCommand(cmdInfo))
{
AfxMessageBox("Failure processing Command Line");
return FALSE;
}
POSITION pos=pDocTemplate->GetFirstDocPosition();
CLCWDoc *pDoc=(CLCWDoc *)pDocTemplate->GetNextDoc(pos);
ASSERT_VALID(pDoc);
POSITION vpos=pDoc->GetFirstViewPosition();
CChildView *pCV=(CChildView *)pDoc->GetNextView(vpos);
if(!cmdInfo.m_Fn1.IsEmpty() && !cmdInfo.m_Fn2.IsEmpty())
{
pCV->OpenF1(cmdInfo.m_Fn1);
pCV->OpenF2(cmdInfo.m_Fn2);
pCV->DoCompare(); // Sends a paint message when complete
}
// enable file manager drag/drop and DDE Execute open
m_pMainWnd->DragAcceptFiles(TRUE);
m_pMainWnd->ShowWindow(SW_SHOWNORMAL);
m_pMainWnd->UpdateWindow(); // paints the window background
pCV->bDoSize=true; //Prevent a dozen useless size calculations
return TRUE;
}
Thanks
Hard to give you good recommendations without knowing what your program shall do. I have only a few general remarks:
Your InitInstance does not look very messed up for me. It's pretty much standard with a bit of custom code in it.
Also the ugly construction to retrieve the first view from the application class (the chain GetDocTemplate -> GetDoc -> GetView) is standard to my knowledge. I actually don't know another way. You might think about moving it into a separate method like CChildView* CLCWApp::GetFirstView() but well, that's only cosmetic as long as you need it only at one place.
What you are doing and which data you are placing in your Document class and in your View class(es) is more a semantic question if you only have one view. (You have only one document anyway because it's an SDI application.). From a technical viewpoint often both is possible.
But to be open for (perhaps) later extensions to more than one view and to follow the standard pattern of a doc/view architecture there are a few rules of thumb:
Data which exist and have a meaning independent of the way to present and view them (a document file, a database handle, etc.) belong to the document class. I don't know what your pCV->OpenF1(cmdInfo.m_Fn1) ... and so on does but if it's something like a file or filename or a parameter to be used to access data in any way OpenF1 might be better a method of the document class.
Methods which do any kind of data processing or modification of your underlying data belong to the document class as well
Data and methods which are only needed for a specific way to display a document belong to a view class (for instance a selected font, colours, etc.)
On the other side: If you have a fixed number of views which open with the document it might not be wrong to put view specific data into the document, especially if you want to make those view parameters persistent. An example would be a file with some statistical data - your document - and a splitter frame with two views: one displays the data as a grid table and the other as a pie chart. The table has "view data" describing the order of and width of columns, the pie chart has data to configure the colours of the pie pieces and the legend location, for instance. If you want to make sure that the user gets the last view configuration displayed when he opens the document file you have to store these view parameters somewhere. It wouldn't be wrong or bad design in my opinion to store those parameters in the document too, to store and retrieve them from any permanent storage, even if you need them only in the view classes.
If your application allows to open an unlimited number of views for a document dynamically and those views are only temporary as long as the application runs, storing all view configuration parameters directly in the view classes seems more natural to me. Otherwise in the document you would need to manage any kind of dynamic data structure and establish a relationship between a View and an entry in this data structure (an index in an array, or a key in a map, etc.)
If you are in doubt whether to place any data in the document or view class I'd prefer the document because you always have the easy GetDocument() accessor in the View class to retrieve members or call methods of the Doc. To fetch data from the View into the Document requires to iterate through the list of views. (Remember: Doc-View is a 1-n relationship, even in a SDI application.)
Just a few cents.

Resources