기타 2009. 2. 2. 14:03
iPhone SDK를 사용하면서 데이터베이스로는 내장된 sqlite3를 조금 사용해 보았습니다. ruby on rails나 이전에 조금 본적은 있지만, 실제로 사용하다 보니 기존의 일반적인인 데이터베이스에 비해 몇가지 재미있고 색다른 부분이 있는 것 같습니다.

1. 특징 & 둘러보기
1) ROWID
SQLite3의 테이블등은 생성시 기본적으로 rowid란 칼럼을 가지고 있습니다. auto increment되는 primary key와 같은 역활을 하지만 vacuum에 의해 변경될 수가 있다고 하니, 이런 용도로는 테이블의 특성에 맞게 사용해야 될 것 같습니다.


select *로는 rowid가 출력되지 않고 명시를 해주어야지 값을 확인할 수있습니다. 마지막으로 인서트된 항목의 rowid는 sqlite3_last_insert_rowid 함수의 반환값으로 확인할 수 있습니다.

2) 데이터 타입
타입이 컬럼에 일괄적으로 적용되는 다른 데이터베이스와는 달리 sqlite3는 각각의 로우별로 동적으로 타입이 결정됩니다. 그렇기 때문에 칼럼타입에 어떤 문자를 주던지 혹은 생략하더라도 테이블 생성이 가능합니다. 아래와 같이 테이블을 만든 후에 어떤 타입의 값들을 넣더라도 모두 저장이 가능합니다.


아래와 같이 각 컬럼의 값들에 따라 데이터타입이 결정됩니다.


한 컬럼에는 기본으로 1GB까지 저장이 가능하며 컴파일시에 SQLITE_MAX_LENGTH 값을 설정하여 2GB까지 가능합니다. 하지만 이전에 간단히 테스트를 해보았는데 OS X에서는 3MB 정도까지만 가능했습니다. 아마 애플에서 제한크기를 낮추어 설치하지 않았나 짐작을 하고 있습니다. 리눅스에서는 몇 백MB까지 인서트가 가능했습니다.

2. 기본 명령어
1) 시작
sqlite는 파일을 기반으로 한 컴팩트한 DB입니다. 대부분의 DB들이 파일을 기반으로 하지만 sqlite3는 데이터베이스 오픈시 인자로 파일을 받습니다.

> sqlite3 [file-name]
파일이 존재할 경우에는 기존 db파일을 열고 존재하지 않을 경우에는 새로 생성합니다. 쉘에서는 쿼리와 구별하여 명령어에 '.'이 접두사로 사용됩니다.

2) 종료
.quit 또는 .exit는 sqlite3를 종료하는 명령어입니다.
sqlite3>.quit
sqlite3>.exit

3) 도움말
sqlite3>.help
sqlite3 쉘에서 사용가능한 명령어들을 보여 줍니다.

4) 테이블 목록
sqlite3>.tables
현재 데이터베이스에 등록된 테이블들의 목록을 확인할 수 있습니다.

5) 스키마 정보
sqlite3>.schema [table-name]
지정된 테이블의 스키마를 확인할 수 있습니다. 테이블명을 입력하지 않으면 모든 테이블의 스키마가 출력됩니다. "ALTER TABLE"도 있는데 add와 rename만 가능한 것 같습니다.

6) 쿼리결과를 파일로 저장
sqlite3>.mode insert
sqlite3>.output db.sql
sqlite3>select * from mytable;
sqlite3>.quit
mode는 출력될 타입을 지정하며 csv, column, html, insert, line, list, tabs, tcl등으로 설정할 수 있습니다. output은 저장될 파일을 지정합니다. 위와 같이 실행 후 종료하면 mytable의 데이터들이 insert로된 sql문으로 db.sql 파일로 저장되어 있습니다.

7) 테이블 변경
sqlite3>alter table [table_name] rename to [new_table_name];
sqlite3>alter table [table_name] add [new_column_name];
alter는 테이블명의 변경과 테이블 컬럼의 추가만 가능한 것 같습니다.

8) vacuum
sqlite3>vacuum
데이터베이스의 테이블의 로우를 재정렬하고 delete, drop으로 인한 빈공간을 제거하는 최적화 작업을 수행합니다. insert, delete, drop등의 명령을 자주 수행하는 DB들은 정기적으로 vacuum을 실행해 주는 것이 좋습니다.

3. 자주 사용되는 C 함수
1) Open & Close
int sqlite3_open(const char *filename, sqlite3 **ppDb);
int sqlite3_close(sqlite3 *pDb);

sqlite3 데이터베이스 파일을 열고 닫는 함수 입니다.

사용 예)
sqlite3 *db;
NSString* path = @"./mydb.sqlite3";

if (sqlite3_open([path UTF8String], &db) != SQLITE_OK)
    NSLog(@"Fail to open sqlite3: %s", sqlite3_errmsg(db));
    sqlite3_close(db);
   
    return NULL;
}

2) 쿼리 실행
nt sqlite3_prepare_v2(sqlite3 *db, const char *zSql, int nByte, sqlite3_stmt **ppStmt, const char **pzTail);
int sqlite3_step(sqlite3_stmt* stmt);
int sqlite3_finalize(sqlite3_stmt *pStmt);

쿼리는 prepare -> step -> finalize의 단계로 실행되고 종료됩니다. prepare는 쿼리실행에 앞서 쿼리를 컴파일하여 바이트코드로 변경합니다. step은 prepare에서 준비된 코드를 실행하며 실행될때 마다 다음 데이터를 가지고 옵니다. finalize는 prepare와 쌍으로 할당된 sqlite3_stmt의 메모리를 해제합니다.

사용 예)
if (sqlite3_prepare_v2(prevDB, "SELECT * FROM cross_temp", -1, &statement, NULL) == SQLITE_OK) {
    while (sqlite3_step(statement) == SQLITE_ROW) {
        int pid = sqlite3_column_int(statement, 0);
        NSLog(@"pid %d", pid);
    }
}
sqlite3_finalize(statement);

3) 결과값
int sqlite3_column_int(sqlite3_stmt*, int iCol);
const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);

스텝에서 각 컬럼의 값들은 column_ 함수로 가져올 수 있습니다. 위는 int와 char*의 예이며 이외에도 각 타입에 맞는 함수들이 제공됩니다.

4) 쿼리 실행 - exec
int sqlite3_exec(sqlite3*, const char *sql, int (*callback)(void*,int,char**,char**), void *, char **errmsg);

exec은 위의 prepare, step, finalize를 동시에 실행하여 편리하게 사용할 수 있습니다. select와 같은 쿼리에서 각 단계의 데이터들은 콜백함수를 구현하여 처리할 수 있습니다.

사용 예)
if (sqlite3_exec(db, "SELECT * FROM item_info limit 10", setData, NULL, &error)) {
    NSLog(@"EXEC ERROR: %s", error);
    sqlite3_free(error);
}

콜백함수의 첫번째 인자는 sqlite3_exec의 4번째 인자에서 넘긴 사용자 데이터가 넘어 옵니다. cols는 전체 컬럼의 갯수이며 value, name에 각각 값과 컬럼명이 넘어 옵니다.
int setData(void* data,int cols, char** value, char** name) {

    for (int i = 0; i < cols; i++) {
        NSLog(@"%s, %s", value[i], name[i]);
    }
    return 0;
}


* 아이폰에서 쓰기 가능한 DB
어플리케이션은 실행시에 번들 내부의 파일에는 쓰기 권한이 없습니다. 그렇기 때문에 번들 내부에 있는 sqlite3 파일은 insert, update, delete와 같은 DB를 변경하는 쿼리가 실행되지 않습니다.

이를 해결하기 위해서는 Documents 디렉토리로 DB파일을 복사하고 이곳의 파일로 열어야 쓰기가 가능합니다. 애플의 아이폰 개발자 센터에 있는 SQLiteBooks 샘플에서 AppDelegate.m의 createEditableCopyOfDatabaseIfNeeded 메소드를 확인하시면 구현에 대해서 잘 나와있습니다. 그리고 아이폰에서 sqlite3 구현에 대한 간단한 내용은 이전 아이폰 SQLite3 샘플이란 포스팅에서 확인하실 수 있습니다.
AND

iOS 2009. 1. 13. 19:49
아이폰 SDK의 UIKit에는 문자열의 출력을 위해 NSString에 추가된 메소드들을 제공합니다. 이를 이용해서 UIView의 drawRect에서 직접 문자열을 출력하는 간단한 방법을 알아 보겠습니다. UIKit에 추가된 NSString의 메소드들에 대한 자세한 설명은 iPhone DevCenterNSString UIKit Additions Reference 문서에서 확인하실 수 있습니다.

1. 폰트 설정

폰트는 UIFont를 사용하여 설정할 수 있습니다. iPhone과 터치에서 사용가능한 폰트는 아래의 소스를 이용하여 확인할 수 있습니다.
NSArray* familyArray = [UIFont familyNames];
for (NSString *familyName in familyArray) {
    NSLog(@"- %@", familyName);  
    NSArray *fontArray = [UIFont fontNamesForFamilyName:familyName];
       
    for (NSString *fontName in fontArray) {
        NSLog(@"%@", fontName);
    }  
}

위 소스를 실행하면 아래와 같이 폰트들의 목록이 출력됩니다. 전체목록은 아래의 '모든 폰트 보기'를 클릭하시면 확인하실 수 있습니다.
- Georgia
Georgia-Bold
Georgia
Georgia-BoldItalic
Georgia-Italic


폰트명을 보면 볼드는 -bold와 이텔릭은 -Italic과 같이 되어 있어 각각의 특징을 알 수 있습니다. 폰트는 일반적으로 UIFont의 아래와 같은 메소드를 사용하여 생성합니다.
+ (UIFont *)fontWithName:(NSString *)fontName size:(CGFloat)fontSize

fontName에는 폰트명을 fontSize에는 크기를 설정하여 UIFont 오브젝트를 생성합니다. 아래는 위의 메소드를 이용하여 19 사이즈의 'Verdana-Bold' 폰트를 생성하는 예입니다.
UIFont *generalFont = [UIFont fontWithName:@"Verdana-Bold" size:19];

한글은 다른 폰트로 설정을 해도 영향을 받지 않는 것 같고 'AppleGothic'만 사용할 수 있는 것 같습니다.
 

2. 컬러 설정

컬러는 UIColor의 'colorWith...' 류의 생성 메소드로 직접 생성할 수 있지만 아래와 같이 미리 지장된 색상을 간편하게 이용할 수도 있습니다.
UIColor *generalColor = [UIColor darkGrayColor];

UIColor에서 지정되어 있는 색상은 아래와 같습니다.
black, darkGray, lightGray, white, gray, red, green, blue, cyan, yellow, magenta, orange,
purple, brown

색상설정은 set을 이용하여 간편하게 적용할 수 있습니다.
[generalColor set]


3. drawAtPoint

지정된 위치에 문자열을 출력하는 간단한 메소드입니다. 반환값은 실제 문자를 출력한 크기입니다.
- (CGSize)drawAtPoint:(CGPoint)point withFont:(UIFont *)font

point에 출력될 위치를 font에 사용될 폰트를 지정합니다.  다소 복잡하지만 아래의 메소드도 많이 사용됩니다.
- (CGSize)drawAtPoint:(CGPoint)point
forWidth:(CGFloat)width
withFont:(UIFont *)font
lineBreakMode:(UILineBreakMode)lineBreakMode

forWith는 문자열이 출력될 너비를 구합니다. fotWidth를 넘어 가는 문자들은 출력되지 않으며, lineBreakMode에 설정된 값에 따라 잘리는 옵션을 선택할 수 있습니다. 옵션은 아래와 같습니다. lineBreakMode의 옵션은 아래와 같습니다.

  • UILineBreakModeWordWrap - 단어 단위
  • UILineBreakModeCharacterWrap - 문자 단위
  • UILineBreakModeClip - 영역
  • UILineBreakModeHeadTruncation - 앞에 '...' 표시
  • UILineBreakModeTailTruncation - 뒤에 '...' 표시
  • UILineBreakModeMiddleTruncation - 중간에 '...' 표시

각 옵션의 결과는 아래의 샘플에서 확인하실 수 있습니다.


4. drawInRect

지정된 영역에 문자를 출력하는 메소드 입니다. 가로정렬이 가능하고 긴 문자열의 경우에는 여러줄에 걸쳐 출력을 할 수 있습니다.
- (CGSize)drawInRect:(CGRect)rect
withFont:(UIFont *)font
lineBreakMode:(UILineBreakMode)lineBreakMode
alignment:(UITextAlignment)alignment

drawAtPoint와 동일하며 alignment의 옵션은 아래와 같습니다.
  • UITextAlignmentLeft - 좌측 정렬
  • UITextAlignmentCenter - 중앙 정렬
  • UITextAlignmentRight - 우측정렬

5. 출력전 크기 구하기

출력전에 미리 출력될 문자열의 크기를 알아 낼 수 있는 'sizeWith...'류의 메소드들을 제공합니다. 출력시 사용하는 font와 width, lineBreakMode과 동일하게 설정하고 호출하면 출력될 텍스트의 실제 크기를 반환합니다.
- (CGSize)sizeWithFont:(UIFont *)font
forWidth:(CGFloat)width
lineBreakMode:(UILineBreakMode)lineBreakMode


drawInRect로 긴 문자열을 여러줄에 출력할 시에는 아래의 메소드를 호출해여 크기를 구해 와야 합니다.
- (CGSize)sizeWithFont:(UIFont *)font
constrainedToSize:(CGSize)size
lineBreakMode:(UILineBreakMode)lineBreakMode


6. 샘플

위의 메소드들을 이용해서 아래와 같이 간단한 예제를 만들어 보겠습니다. drawAtPoint의 breakMode별로 출력하고, 마지막에는 drawInRect를 이용하여 여러행에 걸쳐 출력하도록 하였습니다.
UIView 서브클래스의 drawRect에 아래와 같이 소스를 입력합니다.
- (void)drawRect:(CGRect)rect {
// 시작 x 좌표
#define START_X        10
   
    /* 텍스트 설정 (from wikipedia) */
    NSString *title = @"Tiger";
    NSString *memo = @"The tiger (Panthera tigris) is a member of the Felidae family;" \
                      "the largest of the four big cats";
   
    /* 폰트 설정 */
    UIFont *titleFont = [UIFont fontWithName:@"Arial-BoldItalicMT" size:40];
    UIFont *memoFont = [UIFont fontWithName:@"ArialMT" size:16];
   
    /* 칼라 설정 */
    UIColor *blackColor = [UIColor blackColor];
    UIColor *blueColor = [UIColor blueColor];
    UIColor *redColor = [UIColor redColor];
    UIColor *userColor = [UIColor colorWithRed:0.2 green:0.4 blue:0.2 alpha:0.8];
   
    CGFloat yPosition = 10;
    CGFloat viewWidth = [self bounds].size.width;
    CGSize textSize;
   
    /* 타이틀 출력 */
    [blueColor set];
    textSize = [title drawInRect:CGRectMake(0, yPosition, viewWidth, 30)
                        withFont:titleFont
                   lineBreakMode:UILineBreakModeWordWrap
                       alignment:UITextAlignmentCenter];
    yPosition = (textSize.height + 20);
       
    int mode = 0;   
    NSArray* breakModeArray = [NSArray arrayWithObjects:@"WordWrap",
                               @"CharacterWrap",
                               @"Clip",
                               @"HeadTruncation",
                               @"TailTruncation",
                               @"MiddleTruncation",
                               nil];

    /* breakMode 설정별로 텍스트 출력 */
    [blackColor set];
   
    for (NSString *modeName in breakModeArray) {
        /* 현재 breakMode 출력 */
        [redColor set];
        textSize = [modeName drawAtPoint:CGPointMake(START_X, yPosition)
                                forWidth:viewWidth
                                withFont:memoFont
                           lineBreakMode:UILineBreakModeWordWrap];
        yPosition += textSize.height;
       
        /* 텍스트 출력 */
        [blackColor set];
        textSize = [memo drawAtPoint:CGPointMake(START_X, yPosition)
                            forWidth:viewWidth-80
                            withFont:memoFont
                       lineBreakMode:mode];
        yPosition += (textSize.height + 8);
       
        mode++;
    }
   
    /* drawInRect 타이틀 출력 */
    [redColor set];
    textSize = [@"* drawInRect" drawAtPoint:CGPointMake(START_X, yPosition)
                                   forWidth:viewWidth
                                   withFont:memoFont
                              lineBreakMode:UILineBreakModeWordWrap];
    yPosition += textSize.height;
   
    /* memo를 drawInRect로 출력 */
    [userColor set];
    textSize = [memo drawInRect:CGRectMake(START_X, yPosition, viewWidth-80, 100)
                       withFont:memoFont
                  lineBreakMode:UILineBreakModeWordWrap];
}

AND

맨티스 1.1.1 버젼을 사용하다가 이번에 1.1.6 버젼으로 업그레이드를 했습니다. ChangeLog를 살펴보니 1년동안 업그레이드를 착실히 해온 것 같습니다. 새로운 버젼을 설치 하면서 과정과 사용법을 간단히 정리해 보았습니다.

맨티스 설치사양은 아래와 같습니다.

  • MySQL 4.1.1 이상
  • PHP 4.3.0 이상
  • 아파치, IIS등의 웹서버

1. 다운로드 및 설치
1) 다운로드
맨티스 다운로드 페이지나 혹은 프롬프트 상태에서 아래와 같이 맨티스 설치 파일을 다운로드 받은 후에 압축을 풉니다.
 
> wget http://downloads.sourceforge.net/mantisbt/mantisbt-1.1.6.tar.gz?modtime=1228833846&big_mirror=0
> tar xvzf mantisbt-1.1.6.tar.gz

2) 링크
mantis로 접근하기 위해 압축이 풀린 디렉토리에 심볼릭링크를 걸어줍니다.

> ln -s ./mantisbt-1.1.6 mantis

3) 설치
웹브라우져에서 http://[YOUR-DOMAIN]/mantis/admin/install.php를 실행하여 설치를 시작합니다. 먼저 아래와 같은 첫화면에서 DB 접속정보를 입력합니다.


MySQL 관리자 권한이 있는 계정을 'Admin Username'과 'Admin Password' 필드에 입력하시면 설정한대로 Database와 계정을 생성합니다. 입력을 완료한 후에 'Install/Upgrade Database' 버튼을 클릭합니다.

다음단계에서는 'Write Configuration File(s)'에 오류가 발생합니다. 이는 mantis 루트에 config_inc.php 파일을 생성할 권한이 없어서 입니다. 아래의 작업으로 해결할 수 있습니다.

4) config_inc.php 설정
기존 샘플 파일(config_inc.php.sample)을 아래와 같이 복사합니다.

> mv config_inc.php.sample ./config_inc.php

config_inc.php 파일을 열어 오류메시지에 있는 내용대로 아래와 같이 DB를 설정합니다.
$g_hostname = 'localhost';
$g_db_type = 'mysql';
$g_database_name = 'bugtracker';
$g_db_username = '[USER-NAME]';
$g_db_password = '[USER-PASSWORD]';

기본 메일계정을 설정합니다.
# --- email variables -------------
$g_administrator_email  = 'admin@YOUR-DOMAIN';
$g_webmaster_email      = 'admin@YOUR-DOMAIN';

# the "From: " field in emails
$g_from_email           = 'noreply@YOUR-DOMAIN';

# the return address for bounced mail
$g_return_path_email    = 'admin@YOUR-DOMAIN';

기본으로 한글사용을 위해 아래와 같이 추가합니다.
$g_default_language = "korean";

* admin 디렉토리 삭제
마지막으로 ./admin 디렉토리를 삭제합니다. admin 디렉토리는 초기설치와 관련된 파일들이 위치해 있어 설치후에는 필요가 없이 권한없이 접근할 수 있기 때문에 삭제합니다. 삭제하지 않으면 로그인 화면에서 오류가 표시됩니다.

> rm -dfr ./admin/

5) 로그인
웹브라우져에서 http://YOUR-DOMAIN/mantis 로 들어 갑니다. 아래와 같이 맨티스 사이트가 나오면 오류없이 설치된 것 입니다.

관리자 아이디인 'administrator'와 초기 기본 패스워드인 'root'를 입력하고 로그인 합니다. 관리자 패스워드는 계정관리로 들어가 반드시 변경해야 합니다.

2. 사용자 계정
'관리/사용자 관리' 메뉴로 들어가 '계정생성' 버튼을 클릭하여 사용자를 추가합니다. 계정 생성후에 상세한 옵션이나 권한을 설정할 수 있습니다.


이메일로 계정등록이 발송되기 때문에 이메일 주소를 정확히 입력하셔야 합니다. 테스트를 하여보니 제 서버에서는 이메일이 발송 되지 않았습니다. 

* 이메일 발송 오류
맨티스 루트디렉토리에 있는 config_defaults_inc.php에서 아래의 g_phpMailer_method를 0으로설정되어 있던 것을 아래와 같이 1로 변경하였더니 이메일이 정상적으로 발송되었습니다.

# select the method to mail by:
# 0 - mail()
# 1 - sendmail
# 2 - SMTP
$g_phpMailer_method     = 1;
 
같은서버에 있던 이전 버젼은 0으로 mail()을 사용해도 발송되었는데 이번 버젼에 문제가 있는 것인지 다른 문제가 있는 것인지 모르겠습니다. 저는 0일 경우에는 발송이 안되고 1과 2일 경우에는 발송이 되었습니다.

3. 프로젝트
1) 프로젝트 생성
'관리/프로젝트 관리' 메뉴로 들어가 새로운 프로젝트를 생성합니다. 역시 등록 후에 아래와 같은 상세한 설정을 할 수 있습니다.


2) 서브 프로젝트
연관된 서브프로젝트를 생성하고 관리할 수 있습니다.

3) 버젼
버젼을 등록하고 관리합니다.

3) 분류
이슈등록시 지정할 분류를 관리합니다.

4) 사용자
프로젝트에 관련된 사용자를 추가하고 권한을 설정할 수 있습니다.


4. 이슈 등록 및 확인
1) 사용자 등록
사용자 계정(testID)로 로그인하여 '이슈보고하기' 메뉴를 클릭합니다. 해당 프로젝트를 선택하고 버튼을 클릭하여 필드를 입력하고 등록합니다.


아래는 등록된 이슈목록입니다.

2) 관리자 확인
다시 관리자로 로그인 하면 메인화면에서 새로운 이벤트를 확인할 수 있습니다. 할당되지 않은 이슈에는 담당자를 할당하거나 바로 처리할 수 있습니다.


5. 기타
1) 위키
위키설정은 사실 큰 의미는 없습니다. config_default_inc.php파일에서 g_wiki_enable 속성을 ON으로 하면 메뉴에서 wiki의 링크가 추가됩니다.

#####################
# Wiki Integration
#####################
 
 # Wiki Integration Enabled?
 $g_wiki_enable = ON;

 # Wiki Engine (supported engines: 'dokuwiki', 'mediawiki', 'xwiki')
 $g_wiki_engine = 'dokuwiki';

 # Wiki namespace to be used as root for all pages relating to this mantis installation.
 $g_wiki_root_namespace = 'mantis';

 # URL under which the wiki engine is hosted.  Must be on the same server.
 $g_wiki_engine_url = $t_protocol . '://' . $t_host . '/%wiki_engine%/';

2) 사용자화
웹에서 관리 메뉴와 config_default_inc.php 파일을 변경하여 용도에 맞게 변경할 수 있습니다.

* 커스텀 필드 등록
아래와 같이 사용자 필드를 등록할 수 있습니다. 이외에 권한등 다양한 옵션이 있습니다.

등록된 필드를 프로젝트에 링크하며 해당 프로젝트의 이슈 등록시 사용자 등록필드가 출력됩니다.

* 디자인 변경
core 디렉토리의 html_api.php의 함수들을 수정하여 페이지마다 공통적인 top, bottom과 그외 다른 디자인을 변경할 수 있습니다.

이외에도 공지사항, 문서관리등과 함께 편리하게 이용할 수 있는 기능들이 많이 있습니다. 장단점이 있지만 개인적으로는 Trac보다는 Mantis가 편한 것 같습니다.

'기타' 카테고리의 다른 글

실버라이트2 동영상 재생 속도  (0) 2009.02.13
sqlite3 둘러보기  (3) 2009.02.02
애플스크립트(AppleScript) 둘러보기  (5) 2009.01.06
안드로이드 SDK - 바이오리듬 예제  (5) 2008.12.03
4. 기본 레이아웃 설정  (1) 2008.11.02
AND