Apple's documentation is not as clear as I would like when it comes to understanding subtle details relating to NSFileCoordinator usage. My current interpretation is as follows:
When you access a fileURL using NSFileCoordinator, the coordinator liaises with all registered NSFilePresenters for that fileURL (or hierarchically dependent on that fileURL) and other NSFileCoordinators accessing it as needed to ensure that reads/writes proceed without conflict in an efficient manner (across processes even), taking into account options you specify.
In order to do this, NSFileCoordinator may move the file in order for it to be accessed. Focusing on synchronous coordination of a single fileURL, the accessor block passes a 'newURL' parameter which should be used to access the underlying file or directory.
According to the docs, newURL constitutes:
A URL identifying the file or directory to read/write to. If other objects or processes are acting on the item at the URL, the actual URL passed to reader/writer parameter may be different from the one in this parameter.
I am file coordinating the fileURL of a file package. Within the accessor block I am reading from this file package using the 'newURL' accessor parameter in order to instantiate an object which itself needs to register a file presenter for its parent file package. Consider for example a 'project' object, born from a 'project file package', which needs to present its parent project file package to maintain current knowledge of the project file package location and file coordinate access for future reads/writes.
The question is, should the instantiated object (e.g., project) initialise its file presenter using the original fileURL, or the newURL provided in the accessor block? As far as I can tell there isn't enough information in Apple's docs to really know for sure.
The crux of the confusion:
Example for clarity:
- (instancetype) initProjectWithFilePackageURL:(NSURL *)projectfilePackageURL
{
NSFileCoordinator *fc = [[NSFileCoordinator alloc] initWithFilePresenter:nil];
[fc coordinateReadingItemAtURL:projectFilePackageURL
options:NSFileCoordinatorReadingWithoutChanges
error:&coordinationError
byAccessor:^(NSURL * _Nonnull newURL) {
NSURL *dataURL = fileURLForProjectDataInProjectFilePackageAtURL(newURL);
self = [EGUtility unarchiveProjectFromDataAtURL:dataURL];
if (self)
{
// Which URL should the project present?
// It needs to monitor its parent file package indefinitely, not just within the accessor block.
EGFilePresenter *presenter = [EGPresenter newWithDelegate:project fileURL:<projectFilePackageURL OR newURL>?]
[project setPresenter:presenter];
// Etc…
}
return self;
}
It is difficult to know which I should do, or whether I am missing any other subtleties. I would be very grateful for any insight on this. Thank you.
Having now spent a TSI and discussed the matter with an Apple engineer, here is a summation of what I learned for the benefit of others:
NSFileCoordinator works hard to identify the right URL to pass to the accessor as the newURL. It does the following:
Generally, I was assured that when initialising a file presenter for the coordinated file within the coordinator's accessor block, the URL to use would be the newURL parameter passed to the accessor block unless specifying NSFileCoordinatorReadingForUploading, in which case the coordinated URL should be used instead.