티스토리 뷰

콩글리쉬 실력으로 해석하였으니 영어 고렙분들은 원문을 보시기 바랍니다.

SQLite 조작 개요


다른 데이터베이스들처럼, SQLite는 insert, updating, deleting, selecting SQL 구문을 쓸때 조건절을 지원합니다. Java와 C# 또는 PHP와 같은 다른 언어 처럼 WHERE 절의 값을 파라미터로 표시할 수 있습니다.


아래에 파라미터 표시된 WHERE 절을 가진 SQLite에서 SQL 조각이 있습니다.“?”는 실행시 다른 프로그램 또는 데이터베이스 SQL 구문과 같이 변수,필드,함수, 기타의 실제 값으로 치환됩니다.


Select col1, col2 from database where col1 = ?

다른것은 구문에 값을 저해주는 방법입니다. 구문에 값을 바인드 해야 합니다. 각 데이터 형식에 따라 바인딩하는 방법이 있습니다. 일반적 구문입니다:

int sqlite3_bind_datatype(sqlite3_stmt*, int, datatype);


바인딩


아래는 각 지원 데이터 형식의 바인딩 방법입니다.

  • Text : int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int n, void(*), void(*));
  • Text16 : int sqlite3_bind_text16(sqlite3_stmt*, int, const char*, int n, void(*), void(*));
  • Null : int sqlite3_bind_text(sqlite3_stmt*, int);
  • Blob : int sqlite3_bind_blob(sqlite3_stmt*, int, const char*, int n, void(*), void(*));
  • Int : int sqlite3_bind_int(sqlite3_stmt*, int, int);
  • Int64 : int sqlite3_bind_int64(sqlite3_stmt*, int, int);
  • Double : Int64 : int sqlite3_bind_double(sqlite3_stmt*, int, double);
  • Value : int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value);
  • Zeroblob : int sqlite3_bind_blob(sqlite3_stmt*, int, int n);


CRUD 조작 설정


추가, 수정, 삭제의 실제 운용에 전, 작동을 조종하고 운용하기 위해 Objectice-C 클래스를 만드는것이 필요합니다. CrudOps Objective-C 클래스를 만드는것으로 시작합시다.


헤더파일에 다음의 변수들을 정의하십시오:
...
NSInteger dataId;
NSString *coltext;
NSInteger colint;
double coldbl;
NSFileManager *fileMgr;
NSString *homeDir;
NSString *title;

@property (nonatomic,retain) NSString *title;
@property (nonatomic,retain) NSString *coltext;
@property (nonatomic,retain) NSString *homeDir;
@property (nonatomic, assign) NSInteger dataId;
@property (nonatomic,assign) NSInteger colint;
@property (nonatomic, assign) double coldbl;
@property (nonatomic,retain) NSFileManager *fileMgr;

dataId, coltext, colint, coldbl들은 데이터베이스안의 컬럼을 상징합니다. fileMgr은 리소스 폴더안의 데이터베이스 경로를 얻는 변수 입니다. homeDir은 리소스 폴더가 항상 읽기전용이기에 데이터베이스를 복사할것인 Documents 폴더에 대한 변수입니다. 마지막으로 title 변수는 UIAlertView에 오류메세지를 보여주기 위한것입니다.


다음은 crud 작동을 위한 함수들 설정입니다:

-(void)CopyDbToDocumentsFolder;
-(NSString *) GetDocumentDirectory;
-(void)InsertRecords:(NSMutableString *)txt :(int) integer :(double) dbl;
-(void)UpdateRecords:(NSString *)txt :(NSMutableString *) utxt;
-(void)DeleteRecords:(NSString *)txt;

CopyDbToDocumentFolder 함수는 리소스폴더에서 Documents 폴더로 데이터베이스 복사를 처리할 것입니다. defaultManager에 fileMgr 객체를 설정합니다. 다음줄에서 현재 데이터베이스 경로를 위해 dbPath NSString를 정의합니다. copydbpath NSString은  데이터베이스를 복사할 Documents 디렉토리 목표 경로를 위한 값입니다.


데이터베이스 삭제를 위해 removeItemAtPath 함수를, 리소스 위치에서 새 위치로 데이터베이스 복사를 위해 copyItemAtPath를 사용할것입니다 . 복사 함수가 복사를 할 수 없다면 경고가 사용자에게 보여지게됩니다. 아래는 최고의 코드가 아니지만 작동은 보증됩니다. 다음은 그 함수 코드입니다:


...
-(void)CopyDbToDocumentsFolder{
NSError *err=nil;

fileMgr = [NSFileManager defaultManager];

NSString *dbpath = [[[NSBundle mainBundle] resourcePath]

stringByAppendingPathComponent:@"cruddb.sqlite"];


NSString *copydbpath = [self.GetDocumentDirectory

stringByAppendingPathComponent:@"cruddb.sqlite"];


[fileMgr removeItemAtPath:copydbpath error:&err];

if(![fileMgr copyItemAtPath:dbpath toPath:copydbpath error:&err])
{
UIAlertView *tellErr = [[UIAlertView alloc] initWithTitle:title message:@"Unable to copy

database." delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];

[tellErr show];

}

}
....

GetDocumentDirectory는 Documents 디렉토리 경로를 얻을것입니다. 그곳이 없다면 생성할것입니다. fileMgr 객체는 앱의 홈디렉토리를 얻기위해 NSHomeDirectory() 함수를 사용합니다.

-(NSString *)GetDocumentDirectory{
fileMgr = [NSFileManager defaultManager];
homeDir = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"];

return homeDir;
}
….

레코드 삽입


insert 수행은 매우 간단합니다. 다시 defaultManager에 fileMgr를 설정하는것으로 시작합니다. sqlite3 구문과 데이터베이스에대한 변수들을 선언합시다. 다음으로, SQL 쿼리문장을 위해 const, sql을 정의합니다. 그후, sql3_statement 객체에 있는 데이터베이스와 경로를 엽니다: stmt 와 쿼리문. 한가지 중요한점은 매개변수 구문 색인을 만드는것이 필요하다는것. 각 “bind” 함수 내의 두번째 매개변수를 보면 첫째는 1을, 둘째는 2, 셋째는 3을 가집니다. 이것은 매개변수 구문의 순서를 규정합니다. I know this might be obvious to most while not so obvious for others.


sql3_bind_text, sql3_bind_int, sql3_bind_double들을 사용하여 입력값들을 바인드합니다. sqlite3_step 함수로 쿼리를 적용하고 결국엔 sqlite3_finalize와 sqlite3_close 함수들 각각 호출합니다.


이것들은 우리가 다른 함수들을 보고있을때 주목시키는것과 같이 CRUD (create, update and delete) 작동의 기본과정입니다.



-(void)InsertRecords:(NSMutableString *) txt :(int) integer :(double) dbl{
fileMgr = [NSFileManager defaultManager];
sqlite3_stmt *stmt=nil;
sqlite3 *cruddb;...


//insert
const char *sql = "Insert into data(coltext, colint, coldouble) ?,?,?";

//db 열기
NSString *cruddatabase = [self.GetDocumentDirectory stringByAppendingPathComponent:@"cruddb.sqlite"];
sqlite3_open([cruddatabase UTF8String], &cruddb);
sqlite3_prepare_v2(cruddb, sql, 1, &stmt, NULL);
sqlite3_bind_text(stmt, 1, [txt UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_int(stmt, 2, integer);
sqlite3_bind_double(stmt, 3, dbl);
sqlite3_step(stmt);
sqlite3_finalize(stmt);
sqlite3_close(cruddb); 
}
...

레코드 수정


레코드 수정은 대부분 레코드 삽입의 반복입니다. 유일한 변화는 쿼리문의 구문인데, 레코드 업데이트에 있어서 매우 표준적인 SQL 쿼리문입니다.

-(void)UpdateRecords:(NSString *)txt :(NSMutableString *)utxt{

fileMgr = [NSFileManager defaultManager];
sqlite3_stmt *stmt=nil;
sqlite3 *cruddb;

//insert
const char *sql = "Update data set coltext=? where coltext=?";

//db 열기
NSString *cruddatabase = [self.GetDocumentDirectory stringByAppendingPathComponent:@"cruddb.sqlite"];
sqlite3_open([cruddatabase UTF8String], &cruddb);
sqlite3_prepare_v2(cruddb, sql, 1, &stmt, NULL);
sqlite3_bind_text(stmt, 1, [txt UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 2, [txt UTF8String], -1, SQLITE_TRANSIENT);

sqlite3_step(stmt);
sqlite3_finalize(stmt);
sqlite3_close(cruddb); 

}
….

레코드 삭제


다시 이것은 이전 둘의 반복입니다; 유일하게 다른점은 쿼리문 재실행입니다.


-(void)DeleteRecords:(NSString *)txt{
fileMgr = [NSFileManager defaultManager];
sqlite3_stmt *stmt=nil;
sqlite3 *cruddb;

//insert
const char *sql = "Delete from data where coltext=?";

//Open db
NSString *cruddatabase = [self.GetDocumentDirectory stringByAppendingPathComponent:@"cruddb.sqlite"];
sqlite3_open([cruddatabase UTF8String], &cruddb);
sqlite3_prepare_v2(cruddb, sql, 1, &stmt, NULL);
sqlite3_bind_text(stmt, 1, [txt UTF8String], -1, SQLITE_TRANSIENT);

sqlite3_step(stmt);
sqlite3_finalize(stmt);
sqlite3_close(cruddb); 

}
….

UI 구현


이제 CRUD 운용을위한 클래스와 함수들이 있는데 ViewController 장면 (그림 1)에서 구현이 필요합니다. 이 강좌의 목적을 위해, 3개의 입력란을 만들고 CRUD 하려는 동작의 형식 선택을 사용자에게 허용하기 위해 UISegementedControl을 추가했습니다. 기본으로 UISegmentedControl은 두 부분을 가지고 Momentary를 설정합니다. 우리의 목적을 위해, 추가적 부분을 추가하고 Bar로 이름을 바꿀것입니다. 이런 변경을 만들기위해, UISegmentedControl을 선택하고 Attributes Inspector를 열고 Bar 형식을 변경하고 부분 필드 숫자에 부가적 부분을 추가합니다. 마지막으로 콤보상자의 각 부분들을 선택하고 Insert, Update, Delete로 이름을 변경합니다.

Figure 1: App Layout and Output
그림 1: 앱 화면구성화 출력

TextFields가 설정되었을 때, ViewController에 각 필드 delegate를 만듭니다 (Ctrl+left 마우스 버튼).


다음으로 IBOutlet과 IBAction과 변수들 설정을 위해 kcbViewController 헤더파일로 옮겨갈 것입니다. 기본적으로 UISegmentedControl의 변수, seg를 만들었고 ViewController의 각 항목에 대해 IBOutlet들을 만들었습니다. 그것을 만들때 UISegmentedControl 선택을 위해 Type으로 보존하고 Action을 IBAction으로 변경합시다, “Connect” 클릭하여 연결을 만듭니다.


주: 연결과 위임자 생성방법이 필요하면, 이런 작업들을 이행하는 저의 다른 강좌들을 보아 주십시오. 리턴 버튼 클릭 후에 키보드를 어떻게 닫는가에 대한 단계적 명령도 찾게 될것입니다. 다른 강좌들에대한 링크는 이 강좌의 끝에 있습니다.

kcbViewController 헤더파일에서
...
@interface kcbViewController : UIViewController
{
    UISegmentedControl *seg;
}


@property (weak, nonatomic) IBOutlet UITextField *stringFld;
@property (weak, nonatomic) IBOutlet UITextField *intFld;
@property (weak, nonatomic) IBOutlet UITextField *doubleFld;
@property (weak, nonatomic) IBOutlet UISegmentedControl *seg;

- (IBAction)segButton:(id)sender;

kcbViewController.m 구현파일에서, @synthesize 키워드로 설정자나 접근자를 설정합니다. 마지막으로 CrudOps 객체를 만듭니다, dbCrud를 호출하고 초기화합니다. 그 후 textfield로부터 self.stringFld.text를 NSMutableString로 값을 변경해서 변경될수 있고 CRUD method sin my class의 입력 매개변수와 연결될수 있습니다. 남은 코드는 매우 쉽습니다. UISegmentedControl에서 버튼이 클릭되었는가를 위한 스위치를 selectedSegmentIndex와 CrudOp 클래스의 dbCrud 객체에 대응하는 함수 실행을 사용하여 정의했습니다.


@synthesize stringFld;
@synthesize intFld;
@synthesize doubleFld;


- (IBAction)segButton:(id)sender {
    CrudOp *dbCrud = [[CrudOp alloc] init];
    NSMutableString *fldTxt = [NSMutableString stringWithString:self.stringFld.text];

    switch(self.seg.selectedSegmentIndex)
    {
        case 0:
            [dbCrud InsertRecords:fldTxt :[self.intFld.text intValue] :[self.doubleFld.text doubleValue]];
            break;
        case 1:
            [dbCrud UpdateRecords:self.stringFld.text :fldTxt];
            break;
        case 2:
            [dbCrud DeleteRecords:self.stringFld.text];
            break;
    }
}


소스코드

평소와같이 CrudOp 클래스와 ViewController 클래스 전체 소스코드입니다.

CrudOp.h

//
//  CrudOp.h
//  crud
//
//  Created by Kevin Languedoc on 11/29/11.
//  Copyright (c) 2011 kCodebook. All rights reserved.
//
 
#import <Foundation/Foundation.h>
#import <sqlite3.h>
 
@interface CrudOp : NSObject{
    NSInteger dataId;
    NSString *coltext;
    NSInteger colint;
    double coldbl;
    sqlite3 *db;
    NSFileManager *fileMgr;
    NSString *homeDir;
    NSString *title;
  
 
     
 
}
@property (nonatomic,retain) NSString *title;
@property (nonatomic,retain) NSString *coltext;
@property (nonatomic,retain) NSString *homeDir;
@property (nonatomic, assign) NSInteger dataId;
@property (nonatomic,assign) NSInteger colint;
@property (nonatomic, assign) double coldbl;
@property (nonatomic,retain) NSFileManager *fileMgr;
 
-(void)CopyDbToDocumentsFolder;
-(NSString *) GetDocumentDirectory;
 
-(void)InsertRecords:(NSMutableString *)txt :(int) integer :(double) dbl;
-(void)UpdateRecords:(NSString *)txt :(NSMutableString *) utxt;
-(void)DeleteRecords:(NSString *)txt;
 
 
 
@end

CrudOp.m

//
//  CrudOp.m
//  crud
//
//  Created by Kevin Languedoc on 11/29/11.
//  Copyright (c) 2011 kCodebook. All rights reserved.
//
 
#import "CrudOp.h"
 
@implementation CrudOp
@synthesize  coldbl;
@synthesize colint;
@synthesize coltext;
@synthesize dataId;
@synthesize fileMgr;
@synthesize homeDir;
@synthesize title;
 
 
-(NSString *)GetDocumentDirectory{
    fileMgr = [NSFileManager defaultManager];
    homeDir = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"];
     
    return homeDir;
}
 
-(void)CopyDbToDocumentsFolder{
    NSError *err=nil;
    
    fileMgr = [NSFileManager defaultManager];
    
    NSString *dbpath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"cruddb.sqlite"];
     
    NSString *copydbpath = [self.GetDocumentDirectory stringByAppendingPathComponent:@"cruddb.sqlite"];
     
    [fileMgr removeItemAtPath:copydbpath error:&err];
    if(![fileMgr copyItemAtPath:dbpath toPath:copydbpath error:&err])
    {
        UIAlertView *tellErr = [[UIAlertView alloc] initWithTitle:title message:@"Unable to copy database." delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
        [tellErr show];
 
    }
                
}
 
-(void)InsertRecords:(NSMutableString *) txt :(int) integer :(double) dbl{
    fileMgr = [NSFileManager defaultManager];
    sqlite3_stmt *stmt=nil;
    sqlite3 *cruddb;
     
     
    //insert
    const char *sql = "Insert into data(coltext, colint, coldouble) ?,?,?";
     
    //Open db
    NSString *cruddatabase = [self.GetDocumentDirectory stringByAppendingPathComponent:@"cruddb.sqlite"];
    sqlite3_open([cruddatabase UTF8String], &cruddb);
    sqlite3_prepare_v2(cruddb, sql, 1, &stmt, NULL);
    sqlite3_bind_text(stmt, 1, [txt UTF8String], -1, SQLITE_TRANSIENT);
    sqlite3_bind_int(stmt, 2, integer);
    sqlite3_bind_double(stmt, 3, dbl);
    sqlite3_step(stmt);
    sqlite3_finalize(stmt);
    sqlite3_close(cruddb);   
}
             
-(void)UpdateRecords:(NSString *)txt :(NSMutableString *)utxt{
     
    fileMgr = [NSFileManager defaultManager];
    sqlite3_stmt *stmt=nil;
    sqlite3 *cruddb;
     
     
    //insert
    const char *sql = "Update data set coltext=? where coltext=?";
     
    //Open db
    NSString *cruddatabase = [self.GetDocumentDirectory stringByAppendingPathComponent:@"cruddb.sqlite"];
    sqlite3_open([cruddatabase UTF8String], &cruddb);
    sqlite3_prepare_v2(cruddb, sql, 1, &stmt, NULL);
    sqlite3_bind_text(stmt, 1, [txt UTF8String], -1, SQLITE_TRANSIENT);
    sqlite3_bind_text(stmt, 2, [txt UTF8String], -1, SQLITE_TRANSIENT);
   
    sqlite3_step(stmt);
    sqlite3_finalize(stmt);
    sqlite3_close(cruddb); 
     
}
-(void)DeleteRecords:(NSString *)txt{
     fileMgr = [NSFileManager defaultManager];
    sqlite3_stmt *stmt=nil;
    sqlite3 *cruddb;
     
    //insert
    const char *sql = "Delete from data where coltext=?";
     
    //Open db
    NSString *cruddatabase = [self.GetDocumentDirectory stringByAppendingPathComponent:@"cruddb.sqlite"];
    sqlite3_open([cruddatabase UTF8String], &cruddb);
    sqlite3_prepare_v2(cruddb, sql, 1, &stmt, NULL);
    sqlite3_bind_text(stmt, 1, [txt UTF8String], -1, SQLITE_TRANSIENT);
 
    sqlite3_step(stmt);
    sqlite3_finalize(stmt);
    sqlite3_close(cruddb); 
     
}
 
 
@end

kcbViewController.h

//
//  kcbViewController.h
//  crud
//
//  Created by Kevin Languedoc on 11/29/11.
//  Copyright (c) 2011 kCodebook. All rights reserved.
//
 
#import <UIKit/UIKit.h>
 
@interface kcbViewController : UIViewController
{
    UISegmentedControl *seg;
}
 
 
@property (weak, nonatomic) IBOutlet UITextField *stringFld;
@property (weak, nonatomic) IBOutlet UITextField *intFld;
@property (weak, nonatomic) IBOutlet UITextField *doubleFld;
@property (weak, nonatomic) IBOutlet UISegmentedControl *seg;
 
- (IBAction)segButton:(id)sender;
 
 
 
@end

kcbViewController.m

//
//  kcbViewController.m
//  crud
//
//  Created by Kevin Languedoc on 11/29/11.
//  Copyright (c) 2011 kCodebook. All rights reserved.
//
 
#import "kcbViewController.h"
#import "CrudOp.h"
 
@implementation kcbViewController
@synthesize stringFld;
@synthesize intFld;
@synthesize doubleFld;
 
 
-(void)setSeg:(UISegmentedControl *)seg{
     
}
- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Release any cached data, images, etc that aren't in use.
}
 
#pragma mark - View lifecycle
 
- (void)viewDidLoad
{
    CrudOp *dbCrud = [[CrudOp alloc] init];
    [dbCrud CopyDbToDocumentsFolder];
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
}
 
- (void)viewDidUnload
{
    [self setStringFld:nil];
    [self setIntFld:nil];
    [self setDoubleFld:nil];
    [super viewDidUnload];
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
}
 
- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
}
 
- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
}
 
- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
}
 
- (void)viewDidDisappear:(BOOL)animated
{
    [super viewDidDisappear:animated];
}
 
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    // Return YES for supported orientations
    return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
 
 
 
 
 
- (IBAction)segButton:(id)sender {
    CrudOp *dbCrud = [[CrudOp alloc] init];
    NSMutableString *fldTxt = [NSMutableString stringWithString:self.stringFld.text];
     
    switch(self.seg.selectedSegmentIndex)
    {
        case 0:
            [dbCrud InsertRecords:fldTxt :[self.intFld.text intValue] :[self.doubleFld.text doubleValue]];
            break;
        case 1:
            [dbCrud UpdateRecords:self.stringFld.text :fldTxt];
 
            break;
             
        case 2:
            [dbCrud DeleteRecords:self.stringFld.text];
            break;
    }
}
@end

요약


SQLite를 이용한 SQL 실행은 방법만 알면 매우 쉽습니다. SQLite는 매우 다루기 쉬운 데이터 지속적 저장소를 제공하고 사용하기 매우 쉽습니다. 이 강좌가 도움이 되었기를 바라며 유용한것을 찾았기를 바랍니다.


여기 저의 다른 IOS 5 강좌 링크가 있습니다. 연결과 델리게이트를 만드는 방법들이 포함됩니다. 사용 후 키보드를 사라지게 하는 방법도 있습니다.

IOS 5 SQLite 데이터베이스 응용프로그램 만드는법 | IOS 5 | SQLite

IOS 5 스토리보드 강좌 - Segues | 장면 | View Controllers | Navigation 사용

IOS 5에서 스토리보드 사용법

IOS 5 SDK (Objective-C)에서 파일 읽고 쓰는법 | iPad | iPhone | iPod Touch

댓글