2011年9月9日 星期五

Lala's Program Note 實作記錄: 14. 為文章建立:新增,刪除與編輯功能

since: 2011/09/09
update: 2011/09/22


A. 新增 "新增與編輯" 的介面:
   1. 專案目錄 > New File >
   2. iOS > Cocoa Touch > UIViewController subclass > Next >
   3. Subclass 選擇: UIViewController, 並勾選(預設): With XIB for user interface > Next
   4. Save As: ManageArticleViewController.m

----------------------------------------------------------------------------------------------------------------

B. 開啟 ManageArticleViewController.h 修改如下:
#import <UIKit/UIKit.h>
#import <CoreData/CoreData.h>

@class ArticleListViewController; // 要當作 parenet Controller

@interface ManageArticleViewController : UIViewController {
    IBOutlet UITextField *titleField; // article 標題
    IBOutlet UITextField *subTitleField; // article 副標題
    IBOutlet UITextView *contentText; // article 內容
    ArticleListViewController *parenetController; // A poniter to parent controller
    NSManagedObject *article; // represents the current note
}

@property (nonatomic, retain) IBOutlet UITextField *titleField;
@property (nonatomic, retain) IBOutlet UITextField *subTitleField;
@property (nonatomic, retain) IBOutlet UITextView *contentText;
@property (nonatomic, retain) ArticleListViewController *parenetController;
@property (nonatomic, retain) NSManagedObject *article;

- (id)initWithParentController:(ArticleListViewController *)aParentController article:(NSManagedObject *)anArticle;

- (IBAction)save:(id)sender;
- (IBAction)cancel:(id)sender;
- (IBAction)didEndEdit:(id)sender;
- (IBAction)hitBackground:(id)sender;

@end

----------------------------------------------------------------------------------------------------------------

C. 開啟 ManageArticleViewController.m 修改如下:
#import "ManageArticleViewController.h"
#import "ArticleListViewController.h"

@synthesize titleField, subTitleField, contentText, parenetController, article;

- (IBAction)didEndEdit:(id)sender {
    // 放棄成為第一回應者(鍵盤消失)
    [sender resignFirstResponder];
}

- (IBAction)hitBackground:(id)sender {
    //放棄成為第一回應者(鍵盤消失)
    [titleField resignFirstResponder];
    [subTitleField resignFirstResponder];
    [contentText resignFirstResponder];
}

----------------------------------------------------------------------------------------------------------------

- (id)initWithParentController:(ArticleListViewController *)aParentController article:(NSManagedObject *)anArticle
{
    if ((self = [super init])) {
        self.parenetController = aParentController;
        self.article = anArticle;
    }
    return self;
}

----------------------------------------------------------------------------------------------------------------

- (IBAction)save:(id)sender {
    if (parenetController != nil) {
        /* editing */
        if (article != nil) {
            [article setValue:titleField.text forKey:@"title"];
            [article setValue:subTitleField.text forKey:@"subTitle"];
            [article setValue:contentText.text forKey:@"content"];
            //now date
            [article setValue:[NSDate date] forKey:@"dateUpdate"];
           
            // Save the context
            [parenetController saveContext];
        }
        /* creating a new article */
        else {
            [parenetController insertArticleWithTitle:titleField.text subTitle:subTitleField.text content:contentText.text];
        }
    }
    [self dismissModalViewControllerAnimated:YES];
}


- (IBAction)cancel:(id)sender {
    [self dismissModalViewControllerAnimated:YES];
}

----------------------------------------------------------------------------------------------------------------

- (void)dealloc {
    [parenetController release];
    [article release];
    [super dealloc];
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.
    if (article != nil) {
        titleField.text = [article valueForKey:@"title"];
        subTitleField.text = [article valueForKey:@"subTitle"];
        contentText.text = [article valueForKey:@"content"];
    }
    else {
    }
}

- (void)viewDidUnload
{
    [super viewDidUnload];
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
    self.titleField = nil;
    self.subTitleField = nil;
    self.contentText = nil;
}


D. 建立實際的 UI:

開啟 ManageArticleViewController.xib 檔案, 修改如下:
1. 拖拉一個 Navigation Bar 到 view 上, 對齊 view 最上方的中間,
     將 title 改為: Article.

2. 拖拉二個 Bar Button ItemNavigation Bar 上, 一個放在左邊, 一個放在右邊.
     (1). 分別更改它們的 label, 左邊為: Canel,  右邊為: Save
     (2). 並分別與 File's Owner 上的 cancel:save: 作連結.

3. 拖拉一個 Label 到 view 的左上方, Navigation Bar 的下面, 將其 text 改為: title:

4. 拖拉一個 TextFieldtitle: Label 的右方, 並與 File's Owner
    上的 titleField 作連結.

5. 拖拉一個 Labeltitle: Label 的下方, 將其 text 改為: subTitle:

6. 拖拉一個 TextFieldsubTitle: Label 的右方, 並與 File's Owner
    上的 subTitleField 作連結.

7. 拖拉一個 LabelsubTitle: Label 的下方, 將其 text 改為: content:

8. 拖拉一個 TextViewcontent: Label 的下方, 並與 File's Owner
    上的 contentText 作連結.

----------------------------------------------------------------------------------------------------------------

E. 開啟 ArticleListViewController.h 檔案, 新增二個 method 如下:
- (void)showManageArticleView;
- (void)insertArticleWithTitle:(NSString *)title subTitle:(NSString *)subTitle content:(NSString *)content;

----------------------------------------------------------------------------------------------------------------

F. 開啟 ArticleListViewController.m 檔案, 新增二個 method 如下:
#import "ArticleListViewController.h"
#import "ManageArticleViewController.h"

- (void)showManageArticleView {
    ManageArticleViewController *manageArticleViewController = [[ManageArticleViewController alloc]initWithParentController:self article:nil]; // so a new Article will be created
   
    [self presentModalViewController:manageArticleViewController animated:YES];
    [manageArticleViewController release];
}

----------------------------------------------------------------------------------------------------------------

- (void)insertArticleWithTitle:(NSString *)title subTitle:(NSString *)subTitle content:(NSString *)content { 


    NSManagedObjectContext *context = [fetchedResultsController managedObjectContext];
   
    NSEntityDescription *entity = [[fetchedResultsController fetchRequest] entity];
   
    NSManagedObject *newArticle = [NSEntityDescription insertNewObjectForEntityForName:[entity name] inManagedObjectContext:context];
   
    [newArticle setValue:title forKey:@"title"];
    [newArticle setValue:subTitle forKey:@"subTitle"];

    [newArticle setValue:content forKey:@"content"];
    //Date
    [newArticle setValue:[NSDate date] forKey:@"dateCreated"];
    [newArticle setValue:[NSDate date] forKey:@"dateUpdate"];
   
    //[self.noteBook setValue:newArticle forKey:@"articles"];
    // 'NSInvalidArgumentException', reason: 'Unacceptable type of value for to-many relationship: property = "articles"; desired type = NSSet; given type = NSManagedObject;
   
    //@use NSSet to handle to-many relationship
    NSMutableSet *articles = [self.noteBook mutableSetValueForKey:@"articles"];
    [articles addObject:newArticle];   
   
    // Save the context
    [self saveContext];
}

----------------------------------------------------------------------------------------------------------------

G. 幫 ArticleList 介面增加 "新增" 與 "編輯" 的按鈕.
    開啟 ArticleListViewController.m 檔案, 修改如下:

- (void)viewDidLoad
{
    [super viewDidLoad];

    // Uncomment the following line to preserve selection between presentations.
    // self.clearsSelectionOnViewWillAppear = NO;

    // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
    // self.navigationItem.rightBarButtonItem = self.editButtonItem;
   
    //@add 編輯按鈕 (實際上是進入刪除的功能)
    // 在此處, 會讓 navigation bar 的回上頁消失 (之後再處理 "刪除" 功能)
    //self.navigationItem.leftBarButtonItem = self.editButtonItem;
   
    //@add 新增按鈕
    UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(showManageArticleView)];
   
    self.navigationItem.rightBarButtonItem = addButton;
    [addButton release];
}

----------------------------------------------------------------------------------------------------------------
H. 增加: 編輯 Article 功能:
   開啟 ArticleListViewController.m 檔案, 修改如下:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Navigation logic may go here. Create and push another view controller.
    /*
     <#DetailViewController#> *detailViewController = [[<#DetailViewController#> alloc] initWithNibName:@"<#Nib name#>" bundle:nil];
     // ...
     // Pass the selected object to the new view controller.
     [self.navigationController pushViewController:detailViewController animated:YES];
     [detailViewController release];
     */

    NSManagedObject *article = [[self fetchedResultsController] objectAtIndexPath:indexPath];
   
    ManageArticleViewController *manageArticleViewController = [[ManageArticleViewController alloc] initWithParentController:self article:article];
   
    [self presentModalViewController:manageArticleViewController animated:YES];
    [manageArticleViewController release];
}

----------------------------------------------------------------------------------------------------------------

I. UITextField 輸入結束後, 收起小鍵盤.

  開啟 ManageArticleViewController.xib 檔案:
  將 File's Owner 裡的 didEndEdit: mehod 分別與 UI 的二個 Text Field "Did End On Exit" 做連結.

----------------------------------------------------------------------------------------------------------------

J. 點擊 UITextField 輸入的背景收起小鍵盤.

   開啟 ManageArticleViewController.xib 檔案:
   (1). 將 UIView 的 Class 設定成 UIControl,
         只有 UIControl Class 的控制項才可以觸發動作.
   (2). 將 File's Owner 裡的 hitBackground: mehod
         與剛剛的 UIControl 裡的 Touch Up Inside 作連結.

----------------------------------------------------------------------------------------------------------------

K. 結果圖:
1. 瀏覽文章列表:

2. 新增 Article:

3. 刪除: (在此處, 會讓 navigation bar 的回上頁消失, 之後再處理)

4. 從 Core Data Editor 看儲存的資料:
   NoteBook:

   NoteBook: Relationships -> articles (NoteArticle)

沒有留言:

張貼留言

注意:只有此網誌的成員可以留言。