Core Data-Part2

上一篇中,僅對於基本的Core Data的流程有個初步的概念,但是光看NSLog訊息還是有點生疏,而且依照我目前的程度,是很少去修改到AppDelegate的部份,所以接著嘗試試著修改Master Detail Application看看。

最後的結果是希望可以在Table View中看到我新增的姓名,點選該姓名可以看到該姓名的電話。

**Step 1.**建立Master Detail Application的專案,專案名稱為core data example。

**Step 2.**開啟core_data_example.xcdatamodeld,將原本專案預設的Entity刪除,另外新增一個PhoneEntity,並新增兩個Attributes,name、number,如下圖。

**Step 3.**新增Managed Object Model,對著專案右鍵New FileiOSCore DataNSManagedObjectsubclass,接著會自動新增二個檔案,Phone.mPhone.h

如果沒有直接自動產生,應該會出現以下的畫面,只需要勾選並且下一步即可。

**Step 4.**修改MainStoryboard.storyboard

Navigation的右方加入一個Bar Button Item,點選新增是會跑到上面的畫面,讓我們新增姓名還有電話,下面則是點選姓名時可以看到該姓名的電話。因此需要新增一個AddDetailViewController來控制該新增畫面。在此就不多贅述。

**Step 5.**編輯AddDetailViewController

  1. importPhone.h,因為需要透過它來得知Entitynamenumber
  2. importAppDelegate.h,因為需要使用它裡面的NSManagedObjectContext,所以在此無需重複定義。
  3. 二個UITextField顧名思義就是對應到畫面上二個Text使用的。
  4. app就是要用來引用NSManagedObjectContext
  5. save就是在新增的畫面的Navigation右方,按下save按鈕儲存資料。
AddDetailViewController.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#import <UIKit/UIKit.h>
#import "Phone.h"
#import "AppDelegate.h"
@interface AddDetailViewController : UIViewController
{
UITextField *name_;
UITextField *number_;
}
@property (strong, nonatomic) IBOutlet UITextField *name;
@property (strong, nonatomic) IBOutlet UITextField *number;
@property (retain, nonatomic) AppDelegate *app;

-(IBAction)save:(id)sender;
@end

第5行,取得AppDelegate的delegate

第6行,透過app取得AppDelegete的NSManagedObjectContext

第7行,定義要加入的Entity是Phone。

第9行,用一個if檢查欄位的值是否為空白,當不是空白的時候才寫入。

第18~22,當寫入發生錯誤時才會執行。

AddDetailViewController.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@synthesize name = name_, number = number_, app;

-(IBAction)save:(id)sender
{
app = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [app managedObjectContext];
Phone *phone = [NSEntityDescription insertNewObjectForEntityForName:@"Phone" inManagedObjectContext:context];

if (name_.text.length <= 0 || number_.text.length <= 0 ) {
NSLog(@"Nope");
}
else {
phone.name = name_.text;
phone.number = [NSNumber numberWithInteger:[number_.text integerValue]];
[self.navigationController popViewControllerAnimated:YES];
}

NSError *error;

if (![context save:&error]) {
NSLog(@"Woops");
}
}

**Step 6.**編輯MasterViewController.m

這裡僅需要搜尋Event,並且改成Phone取代(因為Entity已經被我換掉了),還有搜尋timeStamp,並且改成name取代(因為Attribute已經不是timeStamp,我們在Table View中希望呈現姓名,因此改成name)。

最後記得要將viewDidLoad內的方法刪除,僅留下第一行即可(如下)。

MasterViewController.m
1
2
3
4
5
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}

**Step 7.**編輯DetailViewController

因為比原本的專案多了一個UILabel元件,所以要多定義一個,並且找到configureView方法,加入第8行設定detailNumber,而valueForKey記得要修改成跟Entity對應的name、number。

DetailViewController.h
1
2
3
4
5
6
7
8
#import <UIKit/UIKit.h>
@interface DetailViewController : UIViewController

@property (strong, nonatomic) id detailItem;

@property (strong, nonatomic) IBOutlet UILabel *detailDescriptionLabel;
@property (strong, nonatomic) IBOutlet UILabel *detailNumber;
@end
DetailViewController.m
1
2
3
4
5
6
7
8
9
10
@synthesize detailNumber = _detailNumber;

- (void)configureView
{
// Update the user interface for the detail item.
if (self.detailItem) {
self.detailDescriptionLabel.text = [[self.detailItem valueForKey:@"name"] description];
self.detailNumber.text = [[self.detailItem valueForKey:@"number"] description];
}
}

Step 8.建立關連

最後就是將元件跟IBOutletIBAction建立關連,在此就不多做贅述了。

範例下載:Download here