
+ button on the screen to add a new command and an Edit button to delete. Here is the screen:
+ button on the "Command List" screen to add a new command, or when you click on one of the commands from the list to edit it.

+ , a screen for adding a new player to the team appears, and when you click on Edit you can edit the player information.



*.xcdatamodeld in the xcode:
Delete key) an existing Event entity that is not useful to us.Team entity:
Team entity:

Player entity with three attributes:
Team and Player entities, you must first select the Team entity and in the Relationships section, click + and name the new communication players , for the Destination select the Player entity. On the right, set the “To-Many Relationship” flag with the selected players connection. For the delete rule, select Cascade (when deleting a team, all players of the team will be automatically deleted).
Player entity). Add a Player entity connection called team , select Team in the Destination field, and select players in the Invers field (after that, don’t forget to set the Inverse field for the players connection in the Team entity)
Team , and not the Event .MasterViewController.m file, without having forgotten to describe it in MasterViewController.h .MasterViewController.h now looks like this: #import <UIKit/UIKit.h> #import <CoreData/CoreData.h> @interface MasterViewController : UITableViewController <NSFetchedResultsControllerDelegate> @property (nonatomic, strong) NSFetchedResultsController *fetchedResultsController; @property (nonatomic, strong) NSManagedObjectContext *managedObjectContext; - (void)insertTeamWithName:(NSString *)name uniformColor:(NSString *)uniformColor; - (void)saveContext; @end self.title = NSLocalizedString(@"League Manager", @"League Manager"); - (void)insertTeamWithName:(NSString *)name uniformColor:(NSString *)uniformColor { NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext]; NSEntityDescription *entity = [[self.fetchedResultsController fetchRequest] entity]; NSManagedObject *newManagedObject = [NSEntityDescription insertNewObjectForEntityForName:[entity name] inManagedObjectContext:context]; [newManagedObject setValue:name forKey:@"name"]; [newManagedObject setValue:uniformColor forKey:@"uniformColor"]; [self saveContext]; } NSEntityDescription *entity = [NSEntityDescription entityForName:@"Event" inManagedObjectContext:self.managedObjectContext]; NSEntityDescription *entity = [NSEntityDescription entityForName:@"Team" inManagedObjectContext:self.managedObjectContext]; NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] iniWithKey:@"timestamp" ascending:NO]; NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] iniWithKey:@"name" ascending:NO]; [newManagedObject setValue:name forKey:@"name"]; [newManagedObject setValue:uniformColor forKey:@"uniformColor"]; saveContext method is saveContext . - (void)saveContext { NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext]; NSError *error = nil; if(![context save:&error]){ NSLog(@"Unresolved error %@, %@", error, [error userInfo]); abort(); } } - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { if (editingStyle == UITableViewCellEditingStyleDelete) { [self saveContext]; } } Event entities, instead of the required Team entities. We need to display two components in one cell of the table: the name of the team and the color of the form in which this team plays. In order to achieve this, you must first change the style of the displayed table cell, as well as the CellIdentifier identifier used in the cellForRowAtIndexPath: method. static NSString* CellIdentifier = @"Cell"; static NSString* CellIdentifier = @"TeamCell"; cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier]; configureCell:atIndexPath: method is present, in which the cell is actually configured for display. But in the current form, the method works with the essence of the Event , and not the Team , so you need to make some adjustments. - (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath { NSManagedObject *managedObject = [self.fetchedResultsController objectAtIndexPath:indexPath]; cell.textLabel.text = [[managedObject valueForKey:@"name"] description]; cell.detailTextLabel.text = [[managedObject valueForKey:@"uniformColor"] description]; cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton; } Master-Details View Application template, another controller is created called DetailViewController . You can use this class, but since we need to display information about the team and players, it is better to get rid of this controller and create new controllers with appropriate names.#import DetailViewController.h line from MasterViewController.m . Find the tableView:didSelectRowAtIndexPath: method and clean its body. As follows: - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { } DetailViewController (.h, .m, .xib). If we start the application and click on the + button, the application crashes. This + is still bound to the insertNewObject: method that we deleted. We need to attach to this button the ability to create a new team, or rather, to show a modal window with fields for entering information (team name and form color) about the new team. The same window will be used to edit existing commands when you click on a cell with a command on the command list screen.UIViewController :
TeamViewController and don't forget to tick the With XIB for user interface option.
TeamViewController.h . In League Manager, the MasterViewController class manages NSManagedObjectContext , which means in TeamViewController will need a reference to this object management environment and the corresponding initialization method. Since this controller will be responsible for editing the information about the command, during initialization it is worth passing the command object (for this we also need to create a property and add it to the initialization method). The user interface of the command to add / edit a command will contain two text fields - for the name of the command and the color of their form, for them you must create the corresponding properties in TeamViewController . On this screen there will also be two buttons - the save button (Save) of the new command and the Cancel button (Cancel). In TeamViewController should be handler methods for pressing these buttons.TeamViewController.h #import <UIKit/UIKit.h> @class MasterViewController; @interface TeamViewController : UIViewController { IBOutlet UITextField *name; IBOutlet UITextField *uniformColor; NSManagedObject *team; MasterVIewController *masterController; } @property (nonatomic, retain) UITextField *name; @property (nonatomic, retain) UITextField *uniformColor; @property (nonatomic, retain) NSManagedObject *team; @property (nonatomic, retain) MasterViewController *masterController; - (IBAction)save:(id)sender; - (IBAction)cancel:(id)sender; - (id)initWithMasterController:(MasterViewController *)aMasterController team:(NSManagedObject *)aTeam; @end TeamViewController.m , import MasterViewController.h , delete the initWithNibName: , add synthesize for name , team and masterController . Add this initialization method: - (id)initWithMasterController:(MasterController *)aMasterController team:(NSManagedObject *)aTeam { if((self = [super init])){ self.masterController = aMasterController; self.team = aTeam; } return self; } TeamViewController.m controller will be responsible for creating a new NSManagedObject object. In the case, if the user selects one of the existing commands for editing, it is up to the controller to fill in the text fields on the screen with relevant data from the command object (the name of the command and the color of the form). We will add the last functionality to the viewDidLoad method: - (void)viewDidLoad{ [super viewDidLoad]; if(team != nil){ name.text = [team valueForKey:@"name"]; uniformColor.text = [team valueForKey:@"uniformColor"]; } } - (IBAction)save:(id)sender { if(masterController != nil){ if(team != nil){ [team setValue:name.text forKey:@"name"]; [team setValue:uniformColor.text forKey:@"uniformColor"]; [masterController saveContext]; } else { [masterController insertNewTeamWithName:name.text uniformColor:uniformColor.text]; } } [self dismissModalViewControllerAnimated:YES]; } cancel: method cancel: simply removes the command edit / add window.TeamViewController.m #import "TeamViewController.h" #import "MasterViewController.h" @implementation TeamViewController @synthesize name; @synthesize uniformColor; @synthesize team; @synthesize masterController; - (id)initWithMasterController:(MasterController *)aMasterController team:(NSManagedObejct *)aTeam { if((self = [super init])){ self.masterController = aMasterController; self.team = aTeam; } return self; } - (void)didReceiveMemoryWarning{ [super didReceiveMemoryWarning]; } #pragma mark - View lifecycle - (void)viewDidLoad{ [super viewDidLoad]; if(team != nil){ name.text = [team valueForKey:@"name"]; uniformColor.text = [team valueForKey:@"uniformColor"]; } } - (void)viewDidUnload{ [super viewDidUnload]; } - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { return (interfaceOrientation == UIInterfaceOrientationPortrait); } #pragma mark - Button handlers - (IBAction)save:(id)sender{ if(masterController != nil){ if(team != nil){ [team setValue:name.text forKey:@"name"]; [team setValue:uniformColor.text forKey:@"uniformColor"]; [masterController saveContext]; } else { [masterController insertTeamWithName:name.text uniformColor:uniformColor.text]; } } [self dismissModalViewControllerAnimated:YES]; } - (IBAction)cancel:(id)sender{ [self dismissModalViewControllerAnimated:YES]; } @end TeamViewController.xib , it should be empty from the beginning. We install there two inscriptions, two text entry fields and two buttons, we connect the actions of the buttons with the corresponding handler methods. The final view is something like this:
MasterViewController and add the code to display a screen with information about the command. We should display the edit command screen in two cases: 1) the user clicked on + 2) the user clicked on the command from the list. Let's start by pressing the + button. Declare a new method in MasterViewController.h : - (void)showTeamView; MasterViewController.m , import TeamViewController.h and implement the above method as follows: - (void)showTeamView{ TeamViewController *teamViewController = [[TeamViewController alloc] initWithMasterController:self team:nil]; [self presentModalViewController:teamViewController animated:YES]; } viewDidLoad method and replace this code here: UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(insertNewObject)]; UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(showTeamView)]; - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath)indexPath{ NSManagedObject *team = [[self fetchedResultsController] objectAtIndexPath:indexPath]; TeamViewController *teamViewController = [[TeamViewController alloc] initWithMasterController:self team:team]; [self presentModalViewController:teamViewController animated:YES]; } 


NSFetchedResultsController and the rest of the code for working with Core Data, instead they delegate interaction with Core Data MasterViewController .PlayerListViewController controller, set its parent class UITableViewController and uncheck the “With XIB for user interface” option. Open the file PlayerListViewController.h . This class is responsible for displaying the list of players on the team, which means that a reference to the team object is necessary in this class. Also, given the fact that this class delegates interaction with Core Data to the MasterViewController controller, a reference to the controller itself is also needed. #import <UIKit/UIKit.h> @class MasterViewController; @interface PlayerListViewController : UITableVIewController { NSManagedObject *team; MasterViewController *masterViewController; } @property (nonatomic, retain) NSManagedObject *team; @property (nonatomic, retain) MasterViewController *masterController; - (id)initWithMasterController:(MasterViewController *)aMasterController team:(NSManagedObject *)aTeam; - (void)showPlayerView; - (NSArray *)sortPlayers; @end PlayerListViewController.m file and import MasterVIewController.h , synthesize the team and masterController . Change the generated method initWithStyle: to initWithMasterController: which takes two properties and saves as follows: - (id)initWithMasterController:(MasterVIewController *)aMasterVIewController team:(NSManagedObject *)aTeam { if((self = [super init])){ self.masterController = aMasterController; self.team = aTeam; } return self; } viewDidLoad method is viewDidLoad as follows: - (void)viewDidLoad{ [super viewDidLoad]; self.title = @"Player"; UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(showPlayerView)]; self.navigationItem.rightBarButtonItem = addButton; } showPlayerView ’ll leave the showPlayerView method empty for now: - (void)showPlayerView{ } - (void)viewWillAppear:(BOOL)animated{ [super viewWillAppear:animated]; [self.tableView reloadData]; } valueForKey:@"players" method of the team object, which will return NSSet* players to us. Below is the code to customize the table display: - (NSUInteger)numberOfSectionInTableView:(UITableView *)tableView { return 1; } - (NSInteger)tableView:(UITableVIew *)tableView numberOfRowsInSection:(NSInteger)section { return [(NSSet *)[team valueForKey:@"players"] count]; } - (UITableViewCell *)tableView:(UITableVIew *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"PlayerCell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if(cell == nil){ cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier]; } NSManagedObject *player = [[self sortPlayers] objectAtIndex:indexPath.row]; cell.textLabel.text = [NSString stringWithFormat:@"%@ %@", [[player valueForKey:@"firstName"] description], [[player valueForKey:@"lastName"] description]]; cell.detailTextLabel.text = [[player valueForKey:@"email"] description]; return cell; } sortPlayers method, which returns a sorted array of players: - (NSArray *)sortPlayers{ NSSortDescriptor *sortLastNameDescriptor = [[NSSortDescriptor alloc] initWithKey:@"lastName" ascending:YES]; NSArray *sortDescriptors = [NSArray arrayWithObjects:sortLastNameDescriptor, nil]; return [[(NSSet *)[team valueForKey:@"players"] allObjects] sortedArrayUsingDescriptors:sortDescriptors]; } - (void)tableView:(UITableVIew *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath{ NSManagedObject *team = [self.fetchedResultsController objectAtIndexPath:indexPath]; PlayerListViewController *playerListViewController = [[PlayerListViewController alloc] initWithMasterController:self team:team]; [self.navigationController pushViewController:playerListViewController animated:YES]; } PlayerListViewController.h to MasterViewController.m . Now build and run the application. In the list of teams, we see previously created teams, when clicking on the accessory button, a list of players of the selected team opens (while the lists of players are empty, because we have not implemented the addition of a new player).
UIViewController ) with the corresponding XIB and call it PlayerViewController . It will be similar to TeamViewController , but will contain three fields: lastName , firstName and email . The controller also contains a link to MasterViewController in order to be able to use the previously written methods for working with Core Data. There will also be two more properties: the teams in which the player plays and the player himself. If the player's object is nil , then PlayerViewController knows that it is necessary to create a new player, otherwise - edit the player's data. On the screen we will have three buttons: save, cancel and delete. When requesting the removal of a player, we will request confirmation from the user in the form of a UIActionSheeta mapping, so it is imperative that PlayerViewController implement the UIActionSheetDelegate protocol UIActionSheetDelegate . #import <UIKit/UIKit.h> @class MasterViewController; @interface PlayerViewController : UIViewController <UIActionSheetDelegate> { IBOutlet UITextField *firstName; IBOutlet UITextField *lastName; IBOutlet UITextField *email; NSManagedObject *team; NSManagedObject *player; MasterViewController *masterViewController; } @property (nonatomic, retain) UITextField *firstName; @property (nonatomic, retain) UITextField *lastName; @property (nonatomic, retain) UITextField *email; @property (nonatomic, retain) NSManagedObject *team; @property (nonatomic, retain) NSManagedObject *player; @property (nonatomic, retain) MasterViewController *masterController; - (IBAction)save:(id)sender; - (IBAction)cancel:(id)sender; - (IBAction)confirmDelete:(id)sender; - (id)initWithMasterController:(MasterViewController *)aMasterController team:(NSManagedObject *)aTeam player:(NSManagedObject *)aPlayer; @end PlayerViewController.m, import MasterViewController.hand add @synthesizefor all properties from the interface. Add an initialization method to PlayerVIewController.mthat will receive an instance of the class MasterViewController, a team and possibly a player object. - (id)initWithMasterController:(MasterViewController *)aMasterController team:(NSManagedObject *)aTeam player:(NSManagedObject *)aPlayer{ if((self = [super init])){ self.masterController = aMasterController; self.team = team; self.player = player; } return self; } viewDidLoadadd the code to fill in the text fields with the player's data, if it is not equal nil. - (void)viewDidLoad { [super viewDidLoad]; if(player != nil){ firstName.text = [player valueForKey:@"firstName"]; lastName.text = [player valueForKey:@"lastName"]; email.text = [player valueForKey:@"email"]; } } - (IBAction)save:(id)sender{ if(masterController != nil){ if(player != nil){ [player setValue:firstName.text forKey:@"firstName"]; [player setValue:lastName.text forKey:@"lastName"]; [player setValue:email.text forKey:@"email"]; } else { [masterController insertPlayerWithTeam:team firstName:firstName.text lastName:lastName.text email:email.text]; } } [self dismissModelViewControllerAnimated:YES]; } - (IBAction)cancel:(id)sender{ [self dismissModalViewControllerAnimated:YES]; } insertPlayerWithTeam:firstName:lastName:email:in the controller MasterViewControlleryet, but we will write it in just a couple of minutes. First, we implement the confirmDelete:method that is called when you click on the “Delete” button. This method will not immediately remove the player, but he will ask the user for confirmation to perform this action (this is done in order to avoid accidental clicks and deletions of the players). Here is what the method will look like confirmDelete:: - (IBAction)confirmDelete:(id)sender{ if(player != nil){ UIActionSheet *confirm = [[UIActionSheet alloc] initWithTitle:nil delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:@"Delete Player" otherButtonTitles:nil]; confirm.actionSheetStyle = UIActionSheetStyleBlackTranslucent; [confirm showInView:self.view]; } } UIActionSheetwill be the current class. When you click on the button, the UIActionSheetmethod will be called clickedButtonAtIndex:, which means you need to implement it. In the method there will be a check on which button was pressed and, if the button is Delete, then the method (which we will later implement) of the player’s removal will be called: - (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex{ if(buttonIndex == 0 && masterController != nil){ [masterController deletePlayer:player]; [self dismissModalViewControllerAnimated:YES]; } } MasterViewController.hand declare two methods that we have not yet implemented, but have already used: - (void)insertPlayerWithTeam:(NSManagedObject *)team firstName:(NSString *)firstName lastName:(NSString *)lastName email:(NSString *)email; - (void)deletePlayer:(NSManagedObject *)player; MasterViewController.mand implement the methods: - (void)insertPlayerWithTeam:(NSManagedObject *)team firstName:(NSString *)firstName lastName:(NSString *)lastName email:(NSString *)email{ NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext]; NSManagedObject *player = [NSEntityDescription insertNewObjectForEntityForName:@"Player" inManagedObjectContext:context]; [player setValue:firstName forKey:@"firstName"]; [player setValue:lastName forKey:@"lastName"]; [player setValue:email forKey:@"email"]; [player setValue:team forKey:@"team"]; [self saveContext]; } - (void)deletePlayer:(NSManagedObject *)player{ NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext]; [context deleteObject:player]; [self saveContext]; } PlayerViewController.xib, bring it to the look shown in the image below and connect all the Actions with the corresponding buttons.
showPlayerView:that we previously used. Import to PlayerListViewController.mfile PlayerViewController.h. - (void)showPlayerVIew{ PlayerVIewController *playerViewController = [[PlayerVIewController alloc] initWithMasterController:masterController team:team player:nil]; [self presentModalViewController:playerVIewController animated:YES]; } PlayerListViewController.mautomatically generated method didSelectRowAtIndexPath:and bring it to the following form: - (void)tableView:(UITableVIew *)tableVIew didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ NSManagedObject *player = [[self sortPlayers] objectAtIndex:indexPath.row]; PlayerViewController *playerViewController = [[PlayerVIewController alloc] initWithMasterController:masterController team:team player:player]; [self presentModalVIewController:playerViewController animated:YES]; } sqlite3to study the structure of the database that Core Data generates. At the end of the section on working with SQLite storages, we will search our database League_Manager.sqlite3and start sqlite3passing the name of our database as an input parameter. sqlite3 ./5.0/Applications/CE79C20B-4CBF-47C3–9E7C- 9EC24FA22488/Documents/League_Manager.sqlite sqlite3them and them, and see what happens. sqlite> .tables ZPLAYER ZTEAM Z_METADATA Z_PRIMARYKEY ZPLAYERstores entity data Player; ZTEAM- stores entity data Team. sqlite> select * from ZTEAM; 1|2|3|Crew|Blue 2|2|1|Fire|Red 3|2|1|Revolution|Green sqlite> select * from ZPLAYER; 

sqlite3displaying all players in the application: sqlite> select * from ZPLAYER; 1|1|1|1|Jordan|Gordan|jgordon@example.com 2|1|1|1|Pat|Sprat|psprat@example.com 3|1|1|1|Bailey|Staley|bstaley@example.com sqlite> select ZTEAM.ZNAME, ZPLAYER.ZFIRSTNAME, ZPLAYER.ZLASTNAME from ZTEAM, ZPLAYER where ZTEAM.Z_PK = ZPLAYER.ZTEAM; Crew|Jordan|Gordon Crew|Pat|Sprat Crew|Bailey|Staley Fire|Terry|Gary sqlite> select ZTEAM.ZNAME, ZPLAYER.ZFIRSTNAME, ZPLAYER.ZLASTNAME from ZTEAM, ZPLAYER where ZTEAM.Z_PK = ZPLAYER.ZTEAM; Crew|Jordan|Gordon Crew|Bailey|Staley Fire|Terry|Gary sqlite> select ZTEAM.ZNAME, ZPLAYER.ZFIRSTNAME, ZPLAYER.ZLASTNAME from ZTEAM, ZPLAYER where ZTEAM.Z_PK = ZPLAYER.ZTEAM; Crew|Jordan|Gordon Crew|Bailey|Staley NSPersistentStoreCoordinatorspecify a different type when creating it NSSQLiteStoreType.persistentStoreCoordinator:in the League_ManagerAppDelegate.mfile: - (NSPersistentStoreCoordinator *)persistentStoreCoordinator { if(_persistentStoreCoordinator != nil) return _persistentStoreCoordinator; // NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"League_Manager.sqlite"]; NSError *error = nil; _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]]; if(![_persistentStoreCoordinator addPersistentStoreWithType:NSInMemoryStoreType configuration:nil URL:nil options:nil error:&error]){ NSLog(@"Unresolved error %@, %@", error, [error userInfo]); abort(); } return _persistentStoreCoordinator; } Starting with iOS 4 and the introduction of multitasking, switching to another application does not necessarily lead to the termination of your application. Instead of completing, our application continues to work in the background, and therefore the data in the memory continues to remain.

NSAtomicStoreclass (subclass NSPersistentStore) that provides the capabilities (methods) necessary to work with the data. To better understand how this works, imagine the two inner layers inside the Core Data Framework, as shown in the image below:
NSManagedObjectand NSManagedObjectContext. The second layer directly stores the data and contains the data stores and data warehouse coordinator. In the case of custom storage types, the data storage layer also contains NSAtomicStoreCacheNode, which stores objects containing the data itself. Attitude NSAtomicStoreCacheNodetowards NSAtomicStorethe same as NSManagedObjectk NSManagedObjectContext.CustomStore. Add a new class to the League Manager that will inherit from the NSAtomicStore. #import <Foundation/Foundation.h> @interface CustomStore : NSAtomicStore { } @end #import "CustomStore.h" @implementation CustomStore #pragma mark - NSPersistentStore - (NSString *)type { return [[self metadata] objectForKey:NSStoreTypeKey]; } - (NSString *)identifier { return [[self metadata] objectForKey:NSStoreUUIDKey]; } - (id)initWithPersistentStoreCoordinator:(NSPersistentStoreCoordinator *)coordinator configurationName:(NSString *)configurationName URL:(NSURL *)url options:(NSDictionary *)options { self = [super initWithPersistentStoreCoordinator:coordinator configurationName:configurationName URL:url options:options]; return self; } + (NSDictionary *)metadataForPersistentStoreWithURL:(NSURL *)url error:(NSError **)error { return nil; } #pragma mark - NSAtomicStore - (BOOL)load:(NSError **)error { return YES; } - (id)newReferenceObjectForManagedObject:(NSManagedObject *)managedObject { return nil; } - (NSAtomicStoreCacheNode *)newCacheNodeForManagedObject:(NSManagedObject *)managedObject { return nil; } - (BOOL)save:(NSError **)error { return YES; } - (void)updateCacheNode:(NSAtomicStoreCacheNode *)node fromManagedObject:(NSManagedObject *)managedObject { } @end NSPersistentStoreCoordinator'manage different types of vaults. The NSPersistentStoremetadata is presented in the form of a dictionary NSDictionary. The values of the two keys are of particular interest: NSStoreTypeKeyand NSStoreUUIDKey. The value for the key NSStoreTypeKeymust be a unique string identifying the type of storage, and NSStoreUUIDKeythe storage itself. + (NSString *)makeUUID { CFUUIDRef uuidRef = CFUUIDCreate(NULL); CFStringRef uuidStringRef = CFUUIDCreateString(NULL, uuidRef); CFRelease(uuidRef); NSString *uuid = [NSString stringWithString:(__bridge NSString *)uuidStringRef]; CFRelease(uuidStriingRef); return uuid; } metadataForPersistentStoreWithURL:error:. + (void)writeMetadata:(NSDictionary *)metadata toURL:(NSURL *)url { NSString *path = [[url relativePath] stringByAppendingString:@".plist"]; [metadata writeToFile:path atomically:YES]; } NSStoreTypeKey, NSStoreUUIDKey. Find the method metadataForPersistentStoreWithURL:error:and change its body so that it checks for the presence of the metadata file and, if there is no such file, it was created (with the specified keys) along with an empty storage file (text file). + (NSDictionary *)metadataForPersistentStoreWithURL:(NSURL *)url error:(NSError **)error { // determine the filename for metadata file NSString *path = [[url relativePath] stringByAppendingString:@".plist"]; if(![[NSFileManager defaultManager] fileExistsAtPath:path]) { // create a dictionary and store the store type key (CustomStore) // and the UUID key NSMutableDictionary *metadata = [NSMutableDictionary dictionary]; [metadata setValue:@"CustomStore" forKey:NSStoreTypeKey]; [metadata setValue:[CustomStore makeUUID] forKey:NSStoreUUIDKey]; // write the metadata to the .plist file [CustomStore writeMetadata:metadata toURl:url]; // write an empty data file [@"" writeToURL:url atomically:YES encoding:[NSString defaultCStringEncoding] error:nil]; NSLog(@"Created new store at %@", path); } return [NSDictionary dictionaryWithContentsOfFile:path]; } - (id)initWithPersistentStoreCoordinator:(NSPersistentStoreCoordinator *)coordinator configurationName:(NSString *)configurationName URL:(NSURL *)url options:(NSDictionary *)options { self = [super initWithPersistentStoreCoordinator:coordinator configurationName:configurationName URL:url options:options]; NSDictionary *metadata = [CustomStore metadataForPersistentStoreWithURL:[self URL] error:nil]; [self setMetadata:metadata]; return self; } NSManagedObject'. The referencing objects are unique identifiers for each NSAtomicStoreCacheNode'(like the primary key, the relationship is the same as NSObjectIDfor NSManagedObject). Since a custom repository is responsible for translating between NSManagedObject'to NSAtomicStoreCacheNode, it must be able to create a referring object for those just created NSManagedObject'. To do this, we use the UUID again: - (id)newReferenceObjectForManagedObject:(NSManagedObject *)managedObject { NSString *uuid = [CustomStore makeUUID]; return uuid; } NSAtomicStoreCacheNodeclass for the corresponding NSManagedObjectobject. When a new one NSManagedObjectis created and the framework needs to save it, the method is called newReferenceObjectForManagedObject:. NSAtomicCachekeeps track of relationships between NSObjectIDand referencing objects. When Core Data saves NSManagedObjects to local storage, a method is invoked newCacheNodeForManagedObject:that, as can be seen from its name, creates a new instance NSAtomicStoreCacheNodethat serves as an analogue of NSManagedObject. - (NSAtomicStoreCacheNode *)newCacheNodeForManagedObject:(NSManagedObject *)managedObject { NSManagedObjectID *oid = [managedObject objectID]; id referenceID = [self referenceObjectForObjectID:oid]; NSAtomicStoreCacheNode* node = [self nodeForReferenceObject:referenceID andObjectID:oid]; [self updateCacheNode:node fromManagedObject:managedObject]; return node; } newCacheNodeForManagedObject:searches for a referencing object that was created for the corresponding NSManagedObject object and creates a new NSAtomicStoreCacheNode with copying all the fields from the NSManagedObject instance.Source: https://habr.com/ru/post/192960/
All Articles