Core Data Persistent Packages revisited
- Introduction to Core Data, Part IV Storing Fetch Requests in your Data Model. By Jeff LaMarche. In the last Core Data article we talked about creating Fetch Requests programmatically using format strings and predicates. Using format strings to create Fetch Requests is a little bit inelegant, although it does give you a tremendous amount of.
- Introduction to Core Data, Part IV Storing Fetch Requests in your Data Model. By Jeff LaMarche. In the last Core Data article we talked about creating Fetch Requests programmatically using format strings and predicates. Using format strings to create Fetch Requests is a little bit inelegant, although it does give you a tremendous amount of.
19 July 2007
This tutorial teaches ASP.NET Core MVC and Entity Framework Core with controllers and views. Razor Pages is an alternative programming model. For new development, we recommend Razor Pages over MVC with controllers and views. Some developers prefer to use one pattern throughout the data model. In this tutorial, the variation illustrates that. In this video i'm going to show how to insert delete and update data in core data and embedded with navigation and list view in SwiftUI. My Xcode Version is 11.0 My mac OS Version is 10.14.6.
This post is a follow-up to another post I wrote on the very same subject. I am showing here the full implementation of a NSPersistentDocument based class that allows to use package documents embedding a Core Data store.
I short, what this post adds to the previous one is:
Core Data Macos
- improved encapsulation;
- NSDocumentController subclass to correctly handle the Recent Document menus;
- fixed a problem with NSError handling, though still not doing any proper error management.
Those improvements originated from a discussion with Tim Perrett in the cocoa-dev mailing list and from a comment by Laurent Sansonetti to my original post. Thanks to both.
PersistentPackageDocument Class
The PersistentPackageDocument class can be used as a base class for your document classes whenever you want them use a document package embedding the actual Core Data data store. PersistentPackageDocument derives from NSPersistentDocument and overrides four methods: initWithContentsOfURL_ofType_error, writeToURL_ofType_forSaveOperation_originalContentsURL_error, readFromURL_ofType_error, displayname
. Here’s the code:
class PersistentPackageDocument < OSX::NSPersistentDocument
#-- returns the document name to display in the window title
def displayName
if (fileURL)
documentNameFromDataStoreURL(fileURL)
else
'Untitled'
end
end
#-- returns the package document path by stripping the dataStoreName component
#-- from the data store URL; used in displayName
def documentNameFromDataStoreURL(url)
/([^/]+)/?$/ =~ url.relativePath.gsub(/#{dataStoreName}$/, ')
$1 + ' - View'
end
def dataStoreURLFromPackageURL(url)
dataStorePath = url.relativePath.stringByAppendingPathComponent(dataStoreName)
OSX::NSURL.fileURLWithPath(dataStorePath)
end
def readFromURL_ofType_error(url, type, errorPtr)
path=url.relativePath
if (!OSX::NSFileManager.defaultManager.fileExistsAtPath_isDirectory(path, nil))
#-- YOUR ERROR MANAGEMENT HERE
end
result = super_readFromURL_ofType_error(url, type, nil)
if (!result)
#-- SET ERROR INFORMATION TO BE RETURNED VIA errorPtr.assign(nserror_object)
end
result
end
def writeToURL_ofType_forSaveOperation_originalContentsURL_error(url, type, op, content, errorPtr)
#-- if content is not nil, then we are saving a newly created document
#-- in this case, initWithURL is not called, so we had no chance to fix the url,
#-- let's do it here.
if (content nil)
path = url.relativePath
url = dataStoreURLFromPackageURL(url)
isDirectory = false
if (!OSX::NSFileManager.defaultManager.createDirectoryAtPath_attributes(path, nil))
#-- YOUR ERROR MANAGEMENT HERE, set errorPtr
return false
end
end
ok = super_writeToURL_ofType_forSaveOperation_originalContentsURL_error(url, type, op, content, nil)
if (!ok)
#-- SET ERROR INFORMATION TO BE RETURNED VIA errorPtr.assign(nserror_object)
end
ok
end
def initWithContentsOfURL_ofType_error(url, type, errPtr)
url = dataStoreURLFromPackageURL(url)
ok, err = super_initWithContentsOfURL_ofType_error(url, type, nil)
if (!ok)
#-- SET ERROR INFORMATION TO BE RETURNED VIA errorPtr.assign(nserror_object)
end
ok
end
end
For a more detailed discussion of the rationale behind this implementation, see my previous post.
You should then change your MyDocument class (the one produced by XCode templates) so that it derives from PersistentPackageDocument
instead of NSPersistentDocument
and it adds a dataStoreName
method that returns the data store file name for that specific document. Here an example:
class MyDocument < PersistentPackageDocument
Nspersistentdocument Core Data Tutorial For Mac Os
def dataStoreName
'data.xml'
end
#-- default RubyCocoa implementation: managedObjectModel, setManagedObjectContext, windowNibName, etc.
end
Supporting Recent Documents
The PersistentPackageDocumentClass
as given above is fully capable of dealing with package documents embedding a Core Data data store. Unfortunately, it alone cannot ensure that the Recent Documents menu is correctly handled in your application. To that aim, you need to override your NSDocumentController
noteNewRecentDocumentURL
method so that it does some juggling with the path that is stored with the recent document menus.
If your package document is enough rich, chances are that you are already subclassing NSDocumentController
, so overriding noteNewRecentDocumentURL
is a snap. Otherwise, here is a sample subclass:
class PersistentPackageDocumentController < OSX::NSDocumentController
def init
super_init
end
def packageURLFromDataStoreURL(url)
dataStoreName = currentDocument.dataStoreName
OSX::NSURL.fileURLWithPath(url.relativePath.gsub(/#{dataStoreName}$/, '))
end
def noteNewRecentDocumentURL(url)
if (currentDocument)
super_noteNewRecentDocumentURL(packageURLFromDataStoreURL(url))
end
end
end
As already mentioned, the key point is the method noteNewRecentDocumentURL
, while packageURLFromDataStoreURL
is just responsible for string manipulation. Note also that packageURLFromDataStoreURL
accesses the current document to retrieve its dataStoreName
and this forces to guard against the case when there is no current document. There are many alternative implementation of this behaviour, in particular you could define the method dataStoreName
in the document controller class and let PersistentPackageDocument access it there. This approach has the adavantage that a “current” document controller is always there, but for presentation reasons it is not taken here.
Sublassing NSDocumentController
has its own particularities. The easiest way to do it is in Interface Builder MainMenu.nib file. Just subclass and instantiate it in the nib and the above code will be used for your document shared controller. Read this FAQ for more information.
Summing up
The two classes defined above will allow you to easily integrate package documents in your Core Data application.
One final note: make sure you define your document classes as packages in your target properties.
However, when built & go, the code snippet given above will cause a warning as described in the comment. The built is successful, with the compication that the pop-up menu doesn't update the fullNameAndID accordingly. I figured it could have something to do with the formatting string. So referenced relevant document, then found that '%@' could be used with any object. This led me to thought that maybe it's because that employeeID is defined as an integer 32 in the data model. Then I tried to change the last %@ to '%d', but the warning still showed up.
After all that, I'm stuck. So, could anyone help me out with this?!
Thank you very much!
--- Sherlock Asimov
12' Powerbook G4 M9691, Mac OS X (10.5)
Posted on Nov 4, 2007 11:29 PM