Core Data Relationship

Core Data在前面的範例中並沒有使用到Relationship,如果你的資料結構是需要使用到兩個資料表時,這時可以透過Relationship,而且操作起來…我覺得方便很多!假如有表1跟表2是有相關連了,以往我在操作MySQL的時候,會先取得表1的Key值,在拿表1的Key值到表2查詢,這樣等於我要做兩次的SQL查詢(可能有更好的作法吧,我沒有特別去研究…),所以當我用Core Data的時候,覺得這是一個很方便又快速的作法。

接下來我們建立的資料表如下圖。

UserInfo只用來記錄名字,UserDetail則用來記錄該名字的電話、地址、E-mail,而下面Relationship分別為detailinfo

Step 1.編輯xcdatamodeled檔案。

EntityAttributeRelationship的新增就跳過了;這邊需注意的是Relationship設定,除了Destination還須設定Inverse,如下圖。

Step 2.新增Model檔案。

點選UserInfo,在對著專案右鍵/New File/iOS/Core Data/NSManagedObject subclass/Next,接著自動就會產生UserInfo.h與.m的檔案;UserDetail一樣的操作,完成後應該會有四個檔案,分別為UserInfo與UserDetail的.h與.m檔案。

Step 3.編輯MainStoryboard.storyboard檔案。

完成如下圖,新增的時候要輸入姓名、email、電話、地址;顯示則是顯示這四個值。

Step 4.修改MasterViewController.m

記得要把viewDidLoad方法內的執行內容清除,僅需保留[super viewDidLoad];

找到下列三段程式碼,分別修改成對應的Entity名稱與Key值。

MasterViewController.m
1
2
3
4
5
6
7
8
//1
NSEntityDescription *entity = [NSEntityDescription entityForName:@"UserInfo" inManagedObjectContext:self.managedObjectContext];

//2
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:NO];

//3
cell.textLabel.text = [[object valueForKey:@"name"] description];

Step 5.新增AddViewController檔案。

新增一個UIViewController的檔案,class名稱為AddViewController

指定該檔案為新增資料頁面的Class

Step 6.編輯AddViewController.h

編輯程式如下

AddViewController.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#import "UserInfo.h"
#import "UserDetail.h"

@interface AddViewController : UIViewController
@property (strong, nonatomic) IBOutlet UITextField *name;
@property (strong, nonatomic) IBOutlet UITextField *phone;
@property (strong, nonatomic) IBOutlet UITextField *email;
@property (strong, nonatomic) IBOutlet UITextField *address;
- (IBAction)save:(id)sender;

@property (strong, nonatomic) AppDelegate *app;
@end

分別定義四個UITextFieldproperty,一個IBAtcion的save:方法;AppDelegate如同之前說的是要使用AppDelegate內的managedObjectContext

Step 7.編輯AddViewController.m。

編輯程式如下

AddViewController.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@synthesize name, email, phone, address, app;

- (IBAction)save:(id)sender {
app = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [app managedObjectContext];

UserInfo *info = [NSEntityDescription insertNewObjectForEntityForName:@"UserInfo" inManagedObjectContext:context];
info.name = name.text;

UserDetail *detail = [NSEntityDescription insertNewObjectForEntityForName:@"UserDetail" inManagedObjectContext:context];
detail.address = address.text;
detail.email = email.text;
detail.phone = phone.text;
info.detail = detail; //關連

NSError *error;
if (![context save:&error]) {
NSLog(@"Save Error : %@", [error localizedDescription]);
} else {
[self.navigationController popViewControllerAnimated:YES];
}
}

補上synthesize!。這邊可以看到定義一個UserInfoUserDetail的類別變數,分別將TextField的值指定給個別對應的Attribute,這邊可以注意到的是第14行,是透過這樣方式指定兩個表格的對應關連!

Step 8.修改MasterViewController.m

找到prepareForSegue方法,修改的程式如下

MasterViewController.m
1
2
3
4
5
6
7
8
9
10
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:@"showDetail"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];

//修改成UserInfo
UserInfo *object = [[self fetchedResultsController] objectAtIndexPath:indexPath];
[[segue destinationViewController] setDetailItem:object];
}
}

Step 9.修改DetailViewController.h

編輯程式碼如下

DetailViewController.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#import <UIKit/UIKit.h>
#import "UserInfo.h"

@interface DetailViewController : UIViewController

//修改detailItem的形態為UserInfo
@property (strong, nonatomic) UserInfo *detailItem;

@property (weak, nonatomic) IBOutlet UILabel *detailDescriptionLabel;

//多定義3個UILabel元件
@property (strong, nonatomic) IBOutlet UILabel *detailEmail;
@property (strong, nonatomic) IBOutlet UILabel *detailPhone;
@property (strong, nonatomic) IBOutlet UILabel *detailAddress;

@end

Step 10.修改DetailViewController.m

找到configureView方法,修改程式碼如下

DetailViewController.m
1
2
3
4
5
6
7
8
9
10
11
- (void)configureView
{
// Update the user interface for the detail item.

if (self.detailItem) {
self.detailDescriptionLabel.text = [[self.detailItem valueForKey:@"name"] description];
self.detailEmail.text = self.detailItem.detail.email;
self.detailPhone.text = self.detailItem.detail.phone;
self.detailAddress.text = self.detailItem.detail.address;
}
}

如果上述的程式碼有問題的話,不妨檢查一下UserInfo.h的檔案,這邊我發現到自動產生的檔案,他產生的形態並沒有如預期的型態,detail的形態應該是UserDeatail,程式碼如下

UserInfo.h
1
2
3
4
5
6
7
8
9
10
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#import "UserDetail.h"

@interface UserInfo : NSManagedObject

@property (nonatomic, retain) NSString * name;
@property (nonatomic, retain) UserDetail *detail;

@end

Step 11.編譯專案。

最後編譯專案時,記得檢查一下IBOutlet的關聯是否都建立了,如果沒問題,就可以開始新增資料與檢視資料了。