วันพฤหัสบดีที่ 23 ธันวาคม พ.ศ. 2553

UITableView (Basic) Part2

จาก Entry ที่แล้วเราสามารถจะสร้าง TableView ขึ้นมาใช้งานได้
โดยที่เราทำได้คือ การสร้าง Table แสดงข้อมูล การเลือก Row ใน Table
Entry นี้ก็จะมาต่อกันที่การลบนะครับ

เริ่มจากการเปลี่ยนชนิดของตัวแปรที่ใช้เก็บข้อมูลของ Table (_tableData) ก่อนครับ
จาก NSArray เป็น NSMutableArray เพื่อให้เปลี่ยนแปลงแก้ไขข้อมูลได้ครับ  

ส่วนของ interface (.h)
NSMutableArray *_tableData;



ส่วนของ implementation (.m)
_tableData = [[NSMutableArray alloc] initWithObjects:@"Data1", @"Data2", @"Data3", nil];



เพิ่ม Method

-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{
if (editingStyle == UITableViewCellEditingStyleDelete) {
[_tableData removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:YES];
}
}



เราก็จะสามารถลบ Row ใน Table ได้แล้วครับ

ต่อไปก็จะเป็นการทำ Table ที่มีหลายๆ Section นะครับ
เริ่มจากเพิ่ม Property ใน interface

NSArray *_sectionName;



สร้าง Array ใน implementation  (ทำง่ายๆ นะครับ เอาไปประยุกต์ใช้)

_sectionName = [[NSMutableArray alloc] initWithObjects:@"A", @"B", @"C", nil];
_tableData = [[NSMutableArray alloc] initWithObjects:
  [NSMutableArray arrayWithObjects:@"A1", @"A2", @"A3", nil], 
  [NSMutableArray arrayWithObjects:@"B1", @"B2", nil],
  [NSMutableArray arrayWithObjects:@"C1", @"C2", @"C3", @"C4", @"C5", nil], 



ปรับ Code ส่วนของ UITableViewDelegate และ UITableViewDataSource 

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
NSLog(@"%@", [[_tableData objectAtIndex:indexPath.section] objectAtIndex:indexPath.row]);
}

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"tableCell"];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"tableCell"] autorelease];
}
cell.textLabel.text = [[_tableData objectAtIndex:indexPath.section] objectAtIndex:indexPath.row];
return cell;
}

-(NSInteger)tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section{
return [[_tableData objectAtIndex:section] count];
}

เพิ่ม Method -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView

-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return [_tableData count];
}

เพิ่ม Method -(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section

-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{
return [_sectionName objectAtIndex:section];
}

-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{
if (editingStyle == UITableViewCellEditingStyleDelete) {
[[_tableData objectAtIndex:indexPath.section] removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:YES];
}
}



*ย้าย Position ของ UITableView ไว้กลางจอ เพื่อให้เห็นชัด
_tableView.center = window.center;

ลองเอาไปประยุกต์ใช้นะครับ

วันพฤหัสบดีที่ 9 ธันวาคม พ.ศ. 2553

UITableView (Basic)

จะเป็นการสร้าง UITableView แบบง่ายๆ ครับ
เริ่มจากสร้าง Project 
ตั้งชื่อ ผมใช้ชื่อ TableViewBasic




เลือก File TableViewBasicAppDelegate.h
เพิ่ม Protocol และ Property

Protocol
UITableViewDelegate, UITableViewDataSource

Property
UITableView *_tableView;
NSArray *_tableData;



เลือก TableViewBasicAppDelegate.m
ใน Method
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    

สร้าง UITableView
_tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, 200, 400) style:UITableViewStylePlain];
_tableView.delegate = self;
_tableView.dataSource = self;
[window addSubview:_tableView];



สร้าง TableData ที่ต้องการแสดงใน TableView 

_tableData = [[NSArray alloc] initWithObjects:@"Data1", @"Data2", @"Data3", nil];



Implement UITableView Protocol สำคัญ 2 ตัว (เป็นส่วนของ UITableViewDataSource)

เป็น Method สำหรับสร้าง Cell
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"tableCell"];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"tableCell"] autorelease];
}
cell.textLabel.text = [_tableData objectAtIndex:indexPath.row];
return cell;
}
* NSIndexPath จะเก็บ Row และ Section ของ TableView

เป็น Method สำหรับบอกจำนวน Cell
-(NSInteger)tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section{
return [_tableData count];
}


ลอง Build And Run จะมี TableView แสดงข้อมูลใน _tableData ที่สร้างไว้

เวลา Cell ถูกเลือกจะทำงานกับ UITableViewDelegate 

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
NSLog(@"%@", [_tableData objectAtIndex:indexPath.row]);
}



เมื่อเราเลือก Cell ใน Log จะแสดงข้อมูลใน _tableData 


วันศุกร์ที่ 26 พฤศจิกายน พ.ศ. 2553

CoreData Multiple Entity Relationship

สำหรับ Entry นี้จะเป็นเรื่องของการสร้าง Entity มากกว่า 1 ตัวนะครับ
ใน Entry นี้จะไม่ทำเรื่องของ UI นะครับ
จะแสดงแค่วิธีการ เอาไปประยุกต์เองนะครับ

เริ่มจากการเพิ่ม Entity ใน File CoreDataFromTemplate.xcdatamodel
(File .xcdatamodel ที่เราออกแบบตัวเก็ยข้อมูล ดูได้ใน Entry เก่าครับ)
ผมจะเพิ่ม Entity เข้าไป 2 ตัวนะครับ เป็น A กับ B
และทั้ง A และ B จะมี Property name นะครับ



เราจะทำ Relation ระหว่าง A และ B นะครับ
รูปแบบก็เป็น A has_many B ละกันครับ

เริ่มจากเพิ่ม Relationship ใน A และ B ครับ
เลือก Entity A แล้วไปที่ส่วนของ Property กดที่เครื่องหมาย + เลือก Add Relationship
ผมตั้งชื่อว่า bList นะครับ Destination เลือก Entity B เลือกช่อง To-Many Relationship




หลังจากนั้นเลือก Entity B ครับ
เพิ่ม Relationship ใน Property ครับ
ผมตั้งชื่อว่า a นะครับ Destination เลือก Entity A และ Inverse เลือก bList ครับ



Save ครับ

สร้าง File ใหม่ครับ เลือก Add -> New File… เลือก Managed Object Class



ที่หน้าของ Managed Object Class Generation เลือก Entity A และ B กด Finish



จะได้ File เพิ่มมา 4 File 



เริ่มจากเข้าไปที่ MainViewController.h ทำการ Import File ที่เพิ่มขึ้นมา

#import "A.h"
#import "B.h"



ใน MainViewController.m ที่ Method viewDidLoad
ทำการสร้าง A โดยให้ชื่อ A1

A *a = (A *)[NSEntityDescription insertNewObjectForEntityForName:@"A" inManagedObjectContext:managedObjectContext];
a.name = @"A1";
NSError *error;
if (![managedObjectContext save:&error]) {
}



สร้าง Entity B โดยใส่ Entity B เข้าไปใน A ที่สร้างขึ้น
จะมี Method addBListObject: ซึ่งเป้น Method ที่ถูก Generate สามารถดูได้ใน A.h ครับ

B *b = (B *)[NSEntityDescription insertNewObjectForEntityForName:@"B" inManagedObjectContext:managedObjectContext];
b.name = @"B1";
[a addBListObject:b]; // <<<<<
if (![managedObjectContext save:&error]) {
}
b = (B *)[NSEntityDescription insertNewObjectForEntityForName:@"B" inManagedObjectContext:managedObjectContext];
b.name = @"B2";
[a addBListObject:b]; // <<<<<
if (![managedObjectContext save:&error]) {
}



ผมสร้าง B ขึ้นมา 2 ตัวนะครับ B1 และ B2 ใส่เข้าไปใน Object A

การแสดงผล เริ่มจากการเรียกข้อมูล A ก่อน

NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"A" inManagedObjectContext:managedObjectContext];
[request setEntity:entity];
NSMutableArray *aArray = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
if (aArray == nil) {
}
[request release];
[aArray release];



หลังจากนั้นในแต่ละ Entity A จะมี B อยู่ทำการเรียกข้อมูล B จาก A

NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"A" inManagedObjectContext:managedObjectContext];
[request setEntity:entity];
NSMutableArray *aArray = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
if (aArray == nil) {
}
[request release];
// ********************* Begin *************************
NSManagedObject *selectObject;
NSPredicate *predicate;
for (A *a in aArray) {
NSLog(@"*** A %@ ***\n", a.name);
selectObject = a;
predicate = [NSPredicate predicateWithFormat:@"a == %@", selectObject];
request = [[NSFetchRequest alloc] init];
entity = [NSEntityDescription entityForName:@"B" inManagedObjectContext:managedObjectContext];
[request setEntity:entity];
[request setPredicate:predicate];
NSMutableArray *bArray = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
if (bArray == nil) {
}
for (B *b in bArray) {
NSLog(@"B %@", b.name);
}
[request release];
[bArray release];
}
// *********************** End **************************
[aArray release];



จะแสดงข้อมูล A และ B ที่อยู่ใน A ออกมาครับ
การลบนะครับ จะมี Method removeBListObject อยู่ครับ
(ผมแทรกหลัง For ของการแสดง B ครับ)

// ********************* Begin ***********************
selectObject = [aArray objectAtIndex:0];
predicate = [NSPredicate predicateWithFormat:@"a == %@", selectObject];
request = [[NSFetchRequest alloc] init];
entity = [NSEntityDescription entityForName:@"B" inManagedObjectContext:managedObjectContext];
[request setEntity:entity];
[request setPredicate:predicate];
NSMutableArray *bArray = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
if (bArray == nil) {
}
[(A *)selectObject removeBListObject:[bArray objectAtIndex:0]];
[request release];
[bArray release];
// ********************** End ***********************



ถ้าใส่ Code การแสดงผลอีกที B1 จะหายไปครับ
(รูปสุดท้ายเป็น Code ทั้งหมดที่เพิ่มใน viewDidLoad โดยยังไม่มีการแสดงผลรอบ 2 นะครับ)






วันศุกร์ที่ 19 พฤศจิกายน พ.ศ. 2553

CoreData Basic CRUD

ต่อจาก Entry ที่แล้ว นะครับ

สำหรับ Entry นี้จะเป็นเรื่องของ CRUD (Create Read Update Delete) นะครับ
โดยจะต่อจาก Entry ที่แล้วนะครับ

จาก Entry ที่แล้วเราสามารถนำข้อมูลเข้า CoreData ได้แล้ว

-(IBAction) addNew{
MyEntity *myEntity = (MyEntity *)[NSEntityDescription insertNewObjectForEntityForName:@"MyEntity" 
inManagedObjectContext:managedObjectContext];
myEntity.name = _name.text;
NSError *error;
if (![managedObjectContext save:&error]) {
//Handle the error.
}
}

ครั้งนี้เราจะเริ่มจากการนำข้อมูลออกมาแสดงนะครับ
โดยเริ่มผมจะแสดงข้อมูลใน UITableView นะครับ

ขั้นแรกเราก็ทำการสร้าง UITableView ขึ้นมาก่อนนะครับ
เปิด File MainViewController.h

#import <UIKit/UIKit.h>
#import "MyEntity.h"

@interface MainViewController : UIViewController <UITableViewDelegate, UITableViewDataSource> { // <<<< Add Protocol. 
IBOutlet UITextField *_name;
NSManagedObjectContext *managedObjectContext
UITableView *_tableView; // <<<< Add This Line.
}

@property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;

-(IBAction) addNew;
-(IBAction) showData;

@end



สำหรับเรื่องของ UITableView คราวหน้าจะมาเขียนให้นะครับ
คร่าวๆ คือต้องสร้าง tableView และทำการประกาศ Protocol 2 ตัว (เป็นเรื่องของ Delegate Method ลองหาอ่านเพิ่มเติมได้ครับ) 
สร้าง tableView จาก UITableView และมี Protocol ที่เกี่ยวข้องคือ UITableViewDelegate และ UITableViewDataSource

หลังจากนั้นไปที่ MainViewController.m
ทำการสร้าง Table 

- (void)viewDidLoad {
    [super viewDidLoad];
_tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, 300, 400) style:UITableViewStylePlain]; // <<<< Add This Line.
_tableView.center = self.view.center; // <<<< Add This Line.
_tableView.delegate = self; // <<<< Add This Line.
_tableView.dataSource = self; // <<<< Add This Line.
[self.view addSubview:_tableView]; // <<<< Add This Line.
}



เพิ่ม Method สำหรับการ Get ข้อมูล (ในที่นี้ให้เป็น Method ที่ใช้งานภายใน Class MainViewController)

#import "MainViewController.h"

@interface MainViewController (Private)

-(NSArray *)getData;

@end


@implementation MainViewController

@synthesize managedObjectContext; 

-(NSArray *)getData{
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"MyEntity" 
  inManagedObjectContext:managedObjectContext];
[request setEntity:entity];
NSError *error = nil;
NSMutableArray *mutableFetchResults = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
if (mutableFetchResults == nil) {
// Handle the error.
}
[request release];
return [mutableFetchResults autorelease];
}



ทำการ Implement method ของ UITableViewDelegate และ UITableViewDataSource
เพิ่ม Code ใน MainViewController.m

#pragma mark -
#pragma mark UITableViewDelegate And UITableViewDataSource

-(void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
}

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"entityCell"];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"entityCell"] autorelease];
}
cell.textLabel.text = ((MyEntity *)[[self getData] objectAtIndex:indexPath.row]).name;
return cell;
}

-(NSInteger)tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section{
return [[self getData] count];
}



ต่อไปการลบข้อมูลนะครับ
ทำการเพิ่ม Method

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        NSManagedObject *entityToDelete = [[self getData] objectAtIndex:indexPath.row];
[managedObjectContext deleteObject:entityToDelete];
        NSError *error;
if (![managedObjectContext save:&error]) {
// Handle the error.
}
        [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:YES];
    }   
}



ใน Method addNew เพิ่ม [_tableView reloadData]; หลังจากเพิ่มข้อมูล

-(IBAction) addNew{
MyEntity *myEntity = (MyEntity *)[NSEntityDescription insertNewObjectForEntityForName:@"MyEntity" 
inManagedObjectContext:managedObjectContext];
myEntity.name = _name.text;
NSError *error;
if (![managedObjectContext save:&error]) {
//Handle the error.
}
[_tableView reloadData]; // <<<< Add This Line.
}



เรื่องการ Update เพิ่ม Action สำหรับ Update ใน MainViewController.h

#import <UIKit/UIKit.h>
#import "MyEntity.h"

@interface MainViewController : UIViewController <UITableViewDelegate, UITableViewDataSource> { 
IBOutlet UITextField *_name;
NSManagedObjectContext *managedObjectContext
UITableView *_tableView

NSIndexPath *_currentSelect; // <<<< Add This Line.
}

@property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;

-(IBAction) addNew;
-(IBAction) showData;

-(IBAction) update; // <<<< Add This Line.

@end




เพิ่มปุ่ม Update ใน Interface Builder โดยเปิด MainViewController.xib



เชื่อมปุ่ม Update กับ Action update (ctrl+ลาก)

ไปที่ MainViewController.m

เพิ่ม Method update และแก้ไข Code ที่ Method 
-(void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath

เพิ่ม Code 

-(IBAction) update{
NSManagedObject *selectObject = ((MyEntity *)[[self getData] objectAtIndex:_currentSelect.row]);
((MyEntity *)selectObject).name = _name.text;
NSError *error;
if (![managedObjectContext save:&error]) {
//Handle the error.
}
[_tableView reloadData];
}

-(void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
_currentSelect = indexPath;
_name.text = ((MyEntity *)[[self getData] objectAtIndex:indexPath.row]).name;
}



Build And Run

หลังจากเลือกข้อมูลใน Table จะสามารถแก้ไขข้อมูลโดยแก้ไขที่ช่องใส่ข้อมูล