iPhone Development – core data relationships tutorial part 1

简介:

I’m going to start a short series on Core Data relationships and maybe throw in some general Core Data stuff too. Here in part one we’re just going to set our app up with core data and add two entities with a simple one to one relationship between them. A one to one relationship means that for every Fruit there will be one source and in our case here the reverse it true too, for every source there is one fruit.

Core Data Relationships

1.) Create a new Tab Bar Application named CoreDataRelationshipsTutorial.

2.) Change FirstView.xib so it looks similar to this.
FirstView.xib

3.) Add the core data framework to the app.
Add Core Data Framework

4.) Right click on Supporting Files and select New File, then choose Core Data select Data Model and hit Next. I just accepted the default name of Model and clicked save.
Add Data Model

5.) Select Model.xcdatamodeld and the visual editor will open. Click Add Entity and name it Fruit. Add an Attribute named fruitName of type String. Add another Entity named Source with an Attribute sourceName, which will also be of type String.

6.) Select Fruit and then click the plus symbol under Relationships. Name the relationship fruitSource. Set the destination to Source, there will be no inverse yet. In the relationship data model inspector uncheck the Optional checkbox. In the delete rule select Cascade.
Edit Data Model

7.) Now select Source and add a relationship named sourceFruit. Destination should be Fruit and set the inverse to artistCareer. Uncheck the Optional checkbox again.
Set up relationships

8.) Select Fruit under ENTITIES and then go under the file menu up top and select New File. Choose Core Data and NSManagedObject subclass,, click Next. Keep the default location and click Create.
Create Managed Objects

Repeat this same process after selecting Source under ENTITIES.

You should now see your new objects listed under Supporting Files.
xcode view

9.) Open up CoreDataRelationshipsTutorial-Prefix.pch and add an import for CoreDate. This saves us from having to import it into every file that will use it.

1
2
3
4
5
6
7
8
9
10
11
12
#import <availability.h>
 
#ifndef __IPHONE_3_0
#warning "This project uses features only available in iPhone SDK 3.0 and later."
#endif
 
#ifdef __OBJC__
     #import <uikit uikit.h="">
     #import <foundation foundation.h="">
     #import <coredata coredata.h="">
#endif
</coredata></foundation></uikit></availability.h>

10.) Now let’s add all the necessary Core Data code to the app delegate files.

First the header file. Import our FirstViewController, then declare private instance variables for our NSManagedObjectContext, NSManagedObjectModel and NSPersistentStoreCoordinator. Create an IBOutlet with out FirstViewController, and declare two methods that we’ll implement.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#import <uikit uikit.h="">
#import "FirstViewController.h"
 
@interface CoreDataRelationshipsTutorialAppDelegate : NSObject <uiapplicationdelegate, uitabbarcontrollerdelegate= "" >
{
 
@private
     NSManagedObjectContext *managedObjectContext;
     NSManagedObjectModel *managedObjectModel;
     NSPersistentStoreCoordinator *persistentStoreCoordinator;
 
}
 
@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet UITabBarController *tabBarController;
 
@property (nonatomic, retain) IBOutlet FirstViewController *firstViewController;
 
@property (nonatomic, retain, readonly) NSManagedObjectContext *managedObjectContext;
@property (nonatomic, retain, readonly) NSManagedObjectModel *managedObjectModel;
@property (nonatomic, retain, readonly) NSPersistentStoreCoordinator *persistentStoreCoordinator;
 
- (NSURL *)applicationDocumentsDirectory;
- (void)saveContext;
 
@end
</uiapplicationdelegate,></uikit>

11.) Now open the app delegate implementation file. Synthesize our firstViewController, then set it’s managedObjectContext to the one created in the app delegate. You may see an error on the line that sets the managedObjectContext because we haven’t set that up in FirstViewController yet.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#import "CoreDataRelationshipsTutorialAppDelegate.h"
 
@implementation CoreDataRelationshipsTutorialAppDelegate
 
@synthesize window=_window;
@synthesize tabBarController=_tabBarController;
@synthesize firstViewController;
 
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
     firstViewController.managedObjectContext = self.managedObjectContext;
 
     self.window.rootViewController = self.tabBarController;
     [self.window makeKeyAndVisible];
     return  YES;
}

Implement all these methods.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
/**
  Returns the URL to the application's Documents directory.
  */
- (NSURL *)applicationDocumentsDirectory
{
     return  [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
 
- (void)saveContext
{
     
     NSError *error = nil;
     NSManagedObjectContext *objectContext = self.managedObjectContext;
     if  (objectContext != nil)
     {
         if  ([objectContext hasChanges] && ![objectContext save:&error])
         {
             // add error handling here
             NSLog(@ "Unresolved error %@, %@" , error, [error userInfo]);
             abort();
         }
     }
}
 
#pragma mark -
#pragma mark Core Data stack
 
/**
  Returns the managed object context for the application.
  If the context doesn't already exist, it is created and bound to the persistent store coordinator for the application.
  */
- (NSManagedObjectContext *)managedObjectContext
{
     
     if  (managedObjectContext != nil)
     {
         return  managedObjectContext;
     }
     
     NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
     if  (coordinator != nil)
     {
         managedObjectContext = [[NSManagedObjectContext alloc] init];
         [managedObjectContext setPersistentStoreCoordinator:coordinator];
     }
     return  managedObjectContext;
}
 
/**
  Returns the managed object model for the application.
  If the model doesn't already exist, it is created from the application's model.
  */
- (NSManagedObjectModel *)managedObjectModel
{
     if  (managedObjectModel != nil)
     {
         return  managedObjectModel;
     }
     managedObjectModel = [[NSManagedObjectModel mergedModelFromBundles:nil] retain];
     
     return  managedObjectModel;
}
 
/**
  Returns the persistent store coordinator for the application.
  If the coordinator doesn't already exist, it is created and the application's store added to it.
  */
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
     
     if  (persistentStoreCoordinator != nil)
     {
         return  persistentStoreCoordinator;
     }
     
     NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@ "CoreDataTabBarTutorial.sqlite" ];
     
     NSError *error = nil;
     persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
     if  (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error])
     {
         NSLog(@ "Unresolved error %@, %@" , error, [error userInfo]);
         abort();
     }
     
     return  persistentStoreCoordinator;
}

12.) Open up FirstViewController.h and let’s set it up with the necessary code and instance variables.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#import <uikit uikit.h="">
 
@interface FirstViewController : UIViewController
{
     
     NSFetchedResultsController  *fetchedResultsController;
     NSManagedObjectContext      *managedObjectContext;
 
}
 
@property (nonatomic, retain) NSString *fruitNameString;
@property (nonatomic, retain) NSString *fruitSourceString;
 
 
@property (nonatomic, retain) NSFetchedResultsController    *fetchedResultsController;
@property (nonatomic, retain) NSManagedObjectContext        *managedObjectContext;
 
- (IBAction) saveData;
 
@end
</uikit>

13.) Now for the implementation file. Let’s import our managed objects.

1
2
3
#import "FirstViewController.h"
#import "Fruit.h"
#import "Source.h"

Then synthesize the instance variables.

1
2
@synthesize fetchedResultsController, managedObjectContext;
@synthesize fruitNameString, fruitSourceString;

Let’s go ahead and set the values of those two strings in ViewDidLoad.

1
2
3
4
5
6
- (void)viewDidLoad
{
     [ super  viewDidLoad];
     fruitNameString = [[NSString alloc] initWithString:@ "Apple" ];
     fruitSourceString = [[NSString alloc] initWithString:@ "Apple Tree" ];
}

14.) Implement the saveData method.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
- (IBAction) saveData
{
     NSLog(@ "saveData" );
     Fruit *fruit = (Fruit *)[NSEntityDescription insertNewObjectForEntityForName:@ "Fruit"  inManagedObjectContext:managedObjectContext];
     fruit.fruitName = fruitNameString;
     Source *source = (Source *)[NSEntityDescription insertNewObjectForEntityForName:@ "Source"  inManagedObjectContext:managedObjectContext];
     source.sourceName = fruitSourceString;
     
     // Because we set the relationship fruitSource as not optional we must set the source here
     fruit.fruitSource = source;
     
     NSError *error;
     
     // here's where the actual save happens, and if it doesn't we print something out to the console
     if  (![managedObjectContext save:&error])
     {
         NSLog(@ "Problem saving: %@" , [error localizedDescription]);
     }
 
 
     // **** log objects currently in database ****
     // create fetch object, this object fetch's the objects out of the database
     NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
     NSEntityDescription *entity = [NSEntityDescription entityForName:@ "Fruit"  inManagedObjectContext:managedObjectContext];
     [fetchRequest setEntity:entity];
     NSArray *fetchedObjects = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
     
     for  (NSManagedObject *info in  fetchedObjects)
     {
         NSLog(@ "Fruit name: %@" , [info valueForKey:@ "fruitName" ]);
         Source *tempSource = [info valueForKey:@ "fruitSource" ];
         NSLog(@ "Source name: %@" , tempSource.sourceName);
 
     }
     [fetchRequest release];
}

15.) Release our objects in the dealloc method and set them to nil in viewDidUnload.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
- (void)viewDidUnload
{
     [ super  viewDidUnload];
     fetchedResultsController = nil;
     managedObjectContext = nil;
     fruitNameString = nil;
     fruitSourceString = nil;
}
 
- (void)dealloc
{
     [fetchedResultsController release];
     [managedObjectContext release];
     [fruitNameString release];
     [fruitSourceString release];
 
     [ super  dealloc];
}

16.) Open up FirstView.xib and connect the UIButton to our saveData IBAction.

17.) Open up MainWindow.xib, select the app delegate and connect firstViewController outlet to FirstViewController under the Tab Bar Controller.
Link view controller

18.) Now you can run the app and hit the Save Data button. Look in the console to see the results of the fetch.
console

The important things to note from this tutorial are these.

When we created the relationship from Fruit to Source we made it so that it was not optional. Therefore during our saveData method we had to set the fruitSource to something.

1
2
3
4
Fruit *fruit = (Fruit *)[NSEntityDescription insertNewObjectForEntityForName:@ "Fruit"  inManagedObjectContext:managedObjectContext];
fruit.fruitName = fruitNameString;
Source *source = (Source *)[NSEntityDescription insertNewObjectForEntityForName:@ "Source"  inManagedObjectContext:managedObjectContext];
source.sourceName = fruitSourceString;

Try commenting out that last line

1
//    source.sourceName = fruitSourceString;

And then running it again. What happens? Crash and burn. Because the relationship is not optional you must set the sourceName.

You can also see from the block of code above that we use reuse the same managedObjectContext to create both of the managed objects. Then we set the values and just saved the context. Doing this saved both objects (entities in Core Data).

Another thing to take note of happens in the fetch process. You notice that we only fetch the Fruit entity. But because of the relationship between Fruit and Source we can access the Source entity. We don’t need to do a separate fetch on Source.

1
2
3
4
5
6
7
8
9
10
11
12
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@ "Fruit"  inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
NSArray *fetchedObjects = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
 
for  (NSManagedObject *info in  fetchedObjects)
{
     NSLog(@ "Fruit name: %@" , [info valueForKey:@ "fruitName" ]);
     Source *tempSource = [info valueForKey:@ "fruitSource" ];
     NSLog(@ "Source name: %@" , tempSource.sourceName);
     [tempSource release];
}

Okay that does it for this tutorial. Next time we will look at a one to many relationship.

As always here’s the code.

 

欢迎加群互相学习,共同进步。QQ群:iOS: 58099570 | Android: 572064792 | Nodejs:329118122 做人要厚道,转载请注明出处!















本文转自张昺华-sky博客园博客,原文链接:http://www.cnblogs.com/sunshine-anycall/p/3446905.html ,如需转载请自行联系原作者


相关文章
|
存储 数据库 iOS开发
|
1月前
|
编解码 测试技术 iOS开发
iPhone 屏幕尺寸和开发适配
【10月更文挑战第23天】iPhone 的屏幕尺寸变化给开发者带来了一定的挑战,但也为创新提供了机遇。通过深入了解不同屏幕尺寸的特点,遵循适配原则和策略,运用合适的技巧和方法,我们能够为用户提供在不同 iPhone 机型上都具有良好体验的应用。在未来,随着技术的不断进步,我们还需要持续学习和适应,以满足用户对优质应用体验的不断追求。
|
1月前
|
编解码 iOS开发 UED
响应式设计在 iPhone 开发适配中的具体应用
【10月更文挑战第23天】响应式设计在 iPhone 开发适配中扮演着至关重要的角色,它能够帮助我们打造出适应不同屏幕尺寸和用户需求的高质量应用。通过合理运用响应式设计的原则和方法,我们可以在提供良好用户体验的同时,提高开发效率和应用的可维护性。
|
4月前
|
数据采集 iOS开发 Python
Chatgpt教你开发iPhone风格计算器,Python代码实现
Chatgpt教你开发iPhone风格计算器,Python代码实现
|
Shell iOS开发
iOS逆向:tweak开发教程(iPhone/tool)
iOS逆向:tweak开发教程(iPhone/tool)
1262 0
iOS逆向:tweak开发教程(iPhone/tool)
|
编解码 iOS开发
iphone 开发的基本入门知识
iphone 开发的基本入门知识
237 0
「镁客早报」iPhone或将在今年采用三摄;传Facebook致力于开发语音助力服务与亚马逊、苹果竞争
亚马逊向美国Alexa设备推免费音乐服务;视频会议软件开发商Zoom纳斯达克上市。
269 0