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.

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

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

3.) Add the core data framework to the app.

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.

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.

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.

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.

Repeat this same process after selecting Source under ENTITIES.

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

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.

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

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.

iPhone Development – core data relationships tutorial part 1的更多相关文章

  1. 用 SQLite 和 FMDB 替代 Core Data

    本文转载至 http://blog.csdn.net/majiakun1/article/details/38680147 为什么我不使用Core Data Mike Ash 写到: 就个人而言,我不 ...

  2. (转)iphone数据存储之-- Core Data的使用

    原文:http://www.cnblogs.com/xiaodao/archive/2012/10/08/2715477.html iphone数据存储之-- Core Data的使用(一)   一. ...

  3. iphone数据存储之-- Core Data的使用(一)

    http://www.cnblogs.com/xiaodao/archive/2012/10/08/2715477.html 一.概念 1.Core Data 是数据持久化存储的最佳方式 2.数据最终 ...

  4. iphone数据存储之-- Core Data的使用

    一.概念 1.Core Data 是数据持久化存储的最佳方式 2.数据最终的存储类型可以是:SQLite数据库,XML,二进制,内存里,或自定义数据类型 在Mac OS X 10.5Leopard及以 ...

  5. Core Data & MagicalRecord

    iOS 本地数据持久化存储: 1.plist 2.归档 3.NSUserDefaults 4.NSFileManager 5.数据库 一.CoreData概述 CoreData是苹果自带的管理数据库的 ...

  6. 《驾驭Core Data》 第三章 数据建模

    本文由海水的味道编译整理,请勿转载,请勿用于商业用途.    当前版本号:0.1.2 第三章数据建模 Core Data栈配置好之后,接下来的工作就是设计对象图,在Core Data框架中,对象图被表 ...

  7. 《驾驭Core Data》 第二章 Core Data入门

    本文由海水的味道编译整理,请勿转载,请勿用于商业用途.    当前版本号:0.4.0 第二章 Core Data入门 本章将讲解Core Data框架中涉及的基本概念,以及一个简单的Core Data ...

  8. ios开发:Core Data概述

    Core Data 概述 2005年的四月份,Apple 发布了 OS X 10.4,在这个版本中 Core Data 框架发布了.Core Data本身既不是数据库也不是数据库访问框架.相反,Cor ...

  9. iOS教程:如何使用Core Data – 预加载和引入数据

    这是接着上一次<iOS教程:Core Data数据持久性存储基础教程>的后续教程,程序也会使用上一次制作完成的. 再上一个教程中,我们只做了一个数据模型,之后我们使用这个数据模型中的数据创 ...

随机推荐

  1. Sqoop修改sqoop元信息实现job的增量导入

    最简单方式是按主键增量导入:http://blog.csdn.net/ggz631047367/article/details/50185319 以下方法只做存档 需求:redis缓存的数据隔段时间往 ...

  2. 【BZOJ】2456 mode(乱搞)

    Description 给你一个n个数的数列,其中某个数出现了超过n div 2次即众数,请你找出那个数. Input 第1行一个正整数n.第2行n个正整数用空格隔开. Output 一行一个正整数表 ...

  3. 存储过程与SQL语句怎么选择

    应用存储过程的优点:1.具有更好的性能存储过程是预编译的,只在创建时进行编译,以后每次执行存储过程都不需再重新编译,而一般 SQL 语句每执行一次就编译一次,因此使用存储过程可以提高数据库执行速度.2 ...

  4. PHP对全局变量_GET、_POST中特殊字符的过滤

     $sVariablesOrder = ini_get( 'variables_order' );      $request = array();      //过滤不安全数据   for ( $i ...

  5. vue之slot,组件标签嵌套

    vue之slot,组件标签嵌套 插槽(Slot),在各种vue的ui插件中,经常见到的多个组件标签相互嵌套(如下)就是以此为基础的. <el-col > <el-checkbox & ...

  6. 「小程序JAVA实战」小程序模板在外部页面引用(20)

    转自:https://idig8.com/2018/08/09/xiaochengxu-chuji-20/ 不知道老铁还有印象吗?当时讲模板的时候,是在当前的页面进行模板的应用,如何外部的方式引用模板 ...

  7. linux查找目录下的所有文件中是否含有某个字符串 <zhuan>

    查找目录下的所有文件中是否含有某个字符串 find .|xargs grep -ri "IBM" 查找目录下的所有文件中是否含有某个字符串,并且只打印出文件名 find .|xar ...

  8. django-rest-swagger

    前提工作 pip3 install --user django>=2.0.0 pip3 install --user django-rest-swagger 安装完成之后,创建一个django项 ...

  9. 前端开发之JavaScript基础篇二

    主要内容: 1.流程控制条件语句和switch语句 2.for循环和while循环 3.Break语句和Continue语句 4.数组和数组常用方法 5.函数 6.对象 一.流程控制条件语句和swit ...

  10. 蓝桥杯练习系统算法训练习题加答案java版本

    附上百度文库的链接:http://wenku.baidu.com/view/afb78d36b42acfc789eb172ded630b1c59ee9bf7