본문 바로가기
프로그래밍/iOS

처음부터 iPhone 대화 앱 빌드하기[Simple iPhone Chat]

by 백룡화검 2011. 5. 18.


4000만 개의 iPhone에 기본으로 설치되어 있으니, iOS 애플리케이션 쓰기에 관심이 없다면 이상한 일일 것이다. 하지만 어디에서부터 시작하는가? 대부분의 애플리케이션들은 네트워크에 연결된 상태가 될 것이다. 그러면 대화 애플리케이션과 같이 둘 다에 걸쳐지는 프로젝트는 어떠한가? 이 기사에서는 서버와 클라이언트 컴포넌트 둘 다로 대화 애플리케이션을 빌드하는 방법을 알려준다. iOS 애플리케이션 작성하기에 대해 많이 배울 수 있어 이 기사의 끝 부분에서는 독자가 직접 쓰려고 할 것이 확실하다.

애플리케이션을 빌드하는 것은 솔루션을 아키텍트하는 것으로 시작한다. 그림 1에 iOS 디바이스(이 경우에는 iPhone)가 두 개의 PHP 페이지를 통해 서버로 연결하는 방법의 아키텍처가 표시된다.


그림 1. 대화 앱 클라이언트/서버 아키텍처
add.php 및 messages.php 페이지로 데이터베이스에 연결된 iPhone 클라이언트의 다이어그램


이 두 개의 PHP 페이지인 add.php와 messages.php는 둘 다 데이터베이스에 연결하여 각각 메시지를 게시하고 검색한다. 필자가 제공한 코드에서 데이터베이스는 MySQL이지만, DB2나 독자가 원하는 다른 데이터베이스를 사용할 수 있다.

필자가 사용하는 프로토콜은 XML이다. add.php 페이지는 메시지 게시가 성공했는지 여부를 알리는 XML 메시지를 리턴한다. messages.php 페이지는 서버로 게시된 최신 메시지를 리턴한다.

시작하기 전에 여기에서 앞으로 배울 내용을 살펴보려고 한다.

  • 데이터베이스 액세스. 데이터베이스에 행을 추가하고 이를 검색하도록 PHP를 사용하는 방법을 알려준다.
  • XML 인코딩. 서버 코드는 메시지를 XML로 패키지화하는 방법을 보여준다.
  • iOS 인터페이스 빌드하기. 애플리케이션에 대한 사용자 인터페이스를 빌드하는 것을 살펴본다.
  • 서버 쿼리하기. Objective-C 코드는 GET 요청을 messages.php 페이지에 작성하여 최신 대화 메시지를 받는다.
  • XML 구문 분석하기. iOS 개발자들이 사용 가능한 XML 구문 분석기를 사용하면 messages.php에서부터 리턴된 XML을 구문 분석할 수 있다.
  • 메시지 표시하기. 애플리케이션은 사용자 정의 목록 항목을 사용하여 대화 메시지를 표시한다. 이 접근방식을 통해 iOS 애플리케이션의 룩앤필을 사용자 정의하는 방법에 대한 어느 정도의 통찰력을 부여할 수 있다.
  • 메시지 게시하기. 애플리케이션은 프로세스에 걸쳐 안내하는 add.php를 통해 데이터를 서버에 POST한다.
  • 타이머. 타이머 태스크는 정기적으로 messages.php를 폴하는 데 사용되어, 새 대화 항목들이 도착한 시점을 확인한다.

하나의 예제에 대해서는 내용이 많고, 이는 빌드하려는 아무 유형의 클라이언트 서버iOS 애플리케이션을 개발하기 위해 견실한 도구 세트를 제공해야 한다.

서버 빌드하기

데이터베이스를 작성하여 시작한다. 필자는 이를 "대화(chat)"라고 하겠지만, 독자는 원하는 대로 이름을 지을 수 있다. PHP에서 연결 문자열이 데이터베이스의 이름과 일치하도록 변경하는 것만 확인해야 한다. 애플리케이션이 하나의 테이블을 빌드하는 데 사용하는 SQL 스크립트가 리스트 1에 나와있다.


리스트 1. chat.sql
DROP TABLE IF EXISTS chatitems;
CREATE TABLE chatitems (
    id BIGINT NOT NULL PRIMARY KEY auto_increment,
    added TIMESTAMP NOT NULL,
    user VARCHAR(64) NOT NULL,
    message VARCHAR(255) NOT NULL
);

이 간단한 단일 테이블 데이터베이스에 다음 네 가지의 필드가 있다.

  • 자동 증분 정수인 행의 id
  • 메시지가 추가된 날짜
  • 메시지를 추가한 사용자
  • 메시지의 텍스트 그 자체

이러한 필드의 크기는 내용을 수용하도록 변경할 수 있다.

프로덕션 시스템에서 이름과 비밀번호가 있는 사용자 테이블과 로그인 사용자 인터페이스 및 기타 등등을 가지려고 할 가능성이 있다. 이 예제의 경우 데이터베이스를 간단하게 유지하려고 하였기 때문에 테이블이 한 개만 있다.

첫 번째로 빌드하려는 것은 리스트 2의 add.php 스크립트이다.


리스트 2. add.php
<?php
header( 'Content-type: text/xml' );
mysql_connect( 'localhost:/tmp/mysql.sock', 'root', '' );
mysql_select_db( 'chat' );
mysql_query( "INSERT INTO chatitems VALUES ( null, null, '".
    mysql_real_escape_string( $_REQUEST['user'] ).
    "', '".
    mysql_real_escape_string( $_REQUEST['message'] ).
    "')" );
?>
<success />

이 스크립트는 데이터베이스에 연결하고 게시된 usermessage 필드를 사용하여 메시지를 저장한다. 이는 SQL 구문을 방해할 수 있는 작은 따옴표와 같은 잘못된 문자를 고려하도록 두 개의 값이 빠져 나오는 간단한 INSERT 문이다.

add 스크립트를 테스트하려면 필드를 add.php 스크립트로 간단히 게시하는 리스트 3과 같이 test.html 페이지를 작성한다.


리스트 3. test.html
<html>
<head>
    <title>Chat Message Test Form</title>
</head>
<body>
    <form action="add.php" method="POST">
        User: <input name="user" /><br />
        Message: <input name="message" /><br />
        <input type="submit" />
    </form>
</body>
</html>

이 간단한 페이지는 사용자와 메시지에 대해 두 개의 텍스트 필드가 있는 add.php를 가리키는 양식이 하나만 있다. 그 다음에 게시를 실행하는 Submit 단추가 있다.

test.html 페이지가 설치되면 add.php 스크립트를 테스트할 수 있다. 브라우저에서 테스트 페이지를 가져오면 그림 2와 같은 모양이 되어 User 필드에 "jack"의 값이 표시되고, Message 필드에 "This is a test"와 Submit Query 단추가 표시된다.


그림 2. 메시지를 게시하는 테스트 페이지
User 및 Message 필드와 Submit Query 단추가 있는 페이지의 화면 캡처

여기에서부터 일부 값을 추가하고 Submit Query 단추를 클릭한다. 모두 원활히 작동된다면 그림 3과 같은 모양을 보게 된다.


그림 3. 성공적인 메시지 게시
<success/> 요소가 있는 브라우저에서 본 XML 파일의 화면 캡처

그렇지 않은 경우 PHP 스택 추적을 얻게 될 가능성이 있고, 데이터베이스 연결이 실패했거나 INSERT 문이 작업하지 않음을 알리는 메시지가 표시된다.

메시지 추가 스크립트가 작동하면 메시지 목록을 리턴하는 messages.php 스크립트를 빌드할 시간이다. 이 스크립트는 리스트 4에 표시된다.


리스트 4. messages.php
<?php
header( 'Content-type: text/xml' );
mysql_connect( 'localhost:/tmp/mysql.sock', 'root', '' );
mysql_select_db( 'chat' );
if ( $_REQUEST['past'] ) {
    $result = mysql_query('SELECT * FROM chatitems WHERE id > '.
        mysql_real_escape_string( $_REQUEST['past'] ).
        ' ORDER BY added LIMIT 50');
} else {
    $result = mysql_query('SELECT * FROM chatitems ORDER BY added LIMIT 50' );    
}
?>
<chat>
<?php
while ($row = mysql_fetch_assoc($result)) {
?>
<message added="<?php echo( $row['added'] ) ?>" id="<?php echo( $row['id'] ) ?>">
    <user><?php echo( htmlentities( $row['user'] ) ) ?></user>
    <text><?php echo( htmlentities( $row['message'] ) ) ?></text>
</message>
<?php
}
mysql_free_result($result);
?>
</chat>

이 스크립트는 조금 더 복잡하다. 처음으로 수행하는 것은 쿼리를 모으는 것이다. 여기에 다음과 같은 두 가지 가능성이 있다.

  • past 매개변수가 제공되면 스크립트는 지정된 ID를 넘은 메시지만 리턴한다.
  • past 매개변수가 제공되지 않으면 모든 메시지가 리턴된다.

past 매개변수의 이유는 클라이언트가 더 스마트해지기를 바라기 때문이다. 클라이언트가 이미 본 메시지만 기억하고, 이미 본 것들을 넘은 이러한 메시지만 요청하게 만들려고 한다. 클라이언트 로직은 매우 간편하여 past 매개변수로서 이를 찾고 전송하는 최고값 ID를 유지하기만 한다. 시작부터 값으로 0을 전송할 수 있으며, 이는 아무 것도 지정하지 않는 것과 같다.

스크립트의 나머지 반에서는 쿼리 결과 세트에서부터 레코드의 검색을 수행하고 이를 XML로 인코드한다. 스크립트의 이 부분이 작업한다면 선택한 브라우저에서 페이지를 이동할 때에 그림 4의 모양과 유사하게 될 것이다.


그림 4. 대화 메시지 목록
시간소인, ID, 사용자 및 메시지 텍스트가 포함된 XML로 코딩된 짧은 대화 메시지의 화면 캡처

이는 서버에 필요한 전부이다. 물론, 원하는 로직은 무엇이든지 추가할 수 있고, 추가 채널, 사용자 유효성 검증 및 로그인 기타 등등도 추가할 수 있다. 이 실험적인 대화 앱의 목적 상 이 스크립트는 훌륭하게 작업한다. 이제 이 서버를 사용할 iOS 애플리케이션을 빌드할 수 있다.

클라이언트 빌드하기

iOS IDE는 XCode라고 한다. 없으면 Apple Developer 사이트에서 이를 다운로드해야 한다(참고자료 참조). 가장 최신 프로덕션 버전은 XCode 3이며, 여기 화면 캡처에 바로 이를 사용한다. XCode 4라고 하는 더 최신 버전이 있으며, 이는 사용자 인터페이스 편집기를 IDE로 통합하지만, 그 버전은 지금 여전히 미리보기 모드이다.

XCode가 설치되면 그림 5와 같이 New Project 마법사를 사용하여 애플리케이션을 빌드할 시간이다.


그림 5. 뷰 기반 iPhone 앱 빌드하기
선택한 템플리트 옵션의 화면 캡처: iPhone OS > Application 및 Product > iPhone > View-based Application

시작하기에 가장 간편한 애플리케이션 유형은 뷰 기반 애플리케이션이다. 이 유형의 앱을 통해 선택하는 장소 어디에서나 제어의 위치를 지정하고, 대부분의 UI 디자인을 사용자에게 맡겨 둘 수 있다. 제어를 선택한 후에 iPhone이나 iPad 중 하나를 선택한다. 이 선택은 시뮬레이션하려는 디바이스와 관련이 된다. 코드를 쓸 수 있어 iPhone이나 iPad 또는 나중에 제공되는 다른 i-device Apple에서 작업한다.

Choose를 클릭한 후에 애플리케이션의 이름을 묻는 메시지가 표시된다. 필자는 이를 "OSChatClient"라고 하겠지만, 독자는 원하는 대로 이름을 지정할 수 있다. 이름을 부여한 후에 XCode IDE는 핵심 애플리케이션 파일을 빌드한다. 여기에서부터 한 번 컴파일하고 시작하여 모두 올바르게 표시되는지 확인한다.

사용자 인터페이스 작성하기

애플리케이션이 작성된 후에 인터페이스를 개발할 수 있다. 뷰 제어기 XIB 파일이 있는 곳에서 시작하며, 이는 Resources 폴더에 있다. 그 폴더를 두 번 클릭하여 UI 툴킷인 Interface Builder를 가져온다.


그림 6. 인터페이스 레이아웃
메시지 텍스트 상자, Send 단추 및 대화 항목 목록이 있는 UI의 화면 캡처

그림 6에 필자가 세 개의 제어를 펼쳐 놓은 방법이 표시된다. 맨 위에 전송하려는 메시지를 입력하기 위한 텍스트 상자가 있다. 그 텍스트 상자의 오른쪽에 Send 단추가 있다. 그리고 그 아래에 모든 대화 항목을 표시하는 UITableView 오브젝트가 있다.

Interface Builder에 이를 모두 설정하는 방법에 대해 자세히 살펴볼 수도 있지만, 프로젝트 코드를 다운로드하여 독자 스스로 해보기를 권장한다. 자체 앱을 위해 템플리트로 프로젝트를 자유롭게 사용해보자.

뷰 제어기 작성하기

사용자 인터페이스를 위해 할 일을 다 했다. 다음 태스크는 XCode IDE로 다시 이동하여 리스트 5와 같이 몇 개의 멤버 변수, 특성 및 메소드를 뷰 제어기 클래스 정의로 추가하는 것이다.


리스트 5. iOSChatClientViewController.h
#import <UIKit/UIKit.h>

@interface iOSChatClientViewController : UIViewController 
                             <UITableViewDataSource,UITableViewDelegate>    {
    IBOutlet UITextField *messageText;
    IBOutlet UIButton *sendButton;
    IBOutlet UITableView *messageList;

    NSMutableData *receivedData;
    NSMutableArray *messages;
    int lastId;

    NSTimer *timer;

    NSXMLParser *chatParser;
    NSString *msgAdded;
    NSMutableString *msgUser;
    NSMutableString *msgText;
    int msgId;
    Boolean inText;
    Boolean inUser;
}

@property (nonatomic,retain) UITextField *messageText;
@property (nonatomic,retain) UIButton *sendButton;
@property (nonatomic,retain) UITableView *messageList;

- (IBAction)sendClicked:(id)sender;

@end

맨 위에서부터 UITableViewDataSource와 UITableViewDelegate를 클래스 정의에 추가하였다. 이 코드는 메시지 표시를 구동하는 데 사용된다. 데이터 및 레이아웃 정보 둘 다를 테이블 뷰로 피드하는 데 다시 호출되는 클래스에서 메소드들이 있다

인스턴스 변수는 다섯 가지의 그룹으로 나뉜다. 맨 위에 다양한 UI 요소로의 오브젝트 참조, 전송하는 메시지에 대한 텍스트 필드, 전송 단추 및 메시지 목록이 있다.

아래에 리턴된 XML, 메시지 목록 및 가장 최근에 본 ID를 보유하는 버퍼가 있다. lastID는 0에서 시작하지만 메시지에 대해 보는 최대 ID 값으로 설정된다. 그러면 past 매개변수의 값으로 서버로 다시 전송된다.

타이머는 서버에서부터 새 메시지를 찾는 매 몇 초마다 점화하는 것이다. 그리고 마지막 섹션에는 XML을 구문 분석하기 위해 필요한 멤버 변수들이 모두 포함된다. XML 구문 분석기가 콜백 기반 구문 분석기이므로 많이 있으며, 이는 클래스에서 상태를 많이 보유한다.

아래에 멤버 변수들은 특성이며 클릭 핸들러이다. 이는 Interface Builder로 사용되어 인터페이스 요소들을 이 제어기 클래스에 연결한다. 사실 뷰 제어기에서 이 모두를 통해 Interface Builder로 돌아가서 커넥터 제어를 사용하여 메시지 텍스트, 전송 단추 및 메시지 목록을 해당 특성들에 연결하고 Touch Inside 이벤트를 sendClicked 메소드에 연결하기에 좋은 시간이 될 것이다.

뷰 제어기 코드 빌드하기

뷰 제어기 헤더가 준비되면 프로젝트의 본질에 파고들어 뷰 제어기를 구현할 준비가 된 것이다. 필자는 하나의 파일에 속해 있다 하더라도 몇 가지 목록에 걸쳐서 나누어 각 섹션을 조금 더 쉽게 설명할 수 있다.

첫 번째 섹션인 리스트 6에서 애플리케이션 시작과 뷰 제어기의 초기화를 다룬다.


리스트 6. iOSChatClientViewController.m – 시작하기
#import "iOSChatClientViewController.h"

@implementation iOSChatClientViewController

@synthesize messageText, sendButton, messageList;

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) {
        lastId = 0;
        chatParser = NULL;
    }
    return self;
}

- (BOOL)shouldAutorotateToInterfaceOrientation:
                                       (UIInterfaceOrientation)interfaceOrientation {
    return YES;
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
}

- (void)viewDidUnload {
}

- (void)dealloc {
    [super dealloc];
}

이는 매우 표준적인 iOS 코드이다. 메모리 경고 및 할당 해제와 같이 변수 시스템 이벤트에 대한 일부 콜백이 있다. 프로덕션 앱에서 독자는 이러한 항목을 세련되게 처리하려고 하겠지만, 필자는 이 예제 애플리케이션의 목적 상 문제를 과도하게 복잡하게 만들고 싶지는 않다.

첫 번째 실제적인 태스크는 GET 요청을 messages.php 스크립트로 작성하는 측면에서 나타난다. 리스트 7에서 이에 대한 코드가 표시된다.


리스트 7. iOSChatClientViewController.m – 메시지 받기
- (void)getNewMessages {
    NSString *url = [NSString stringWithFormat:
        @"http://localhost/chat/messages.php?past=%ld&t=%ld",
        lastId, time(0) ];

    NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease];
    [request setURL:[NSURL URLWithString:url]];
    [request setHTTPMethod:@"GET"];

    NSURLConnection *conn=[[NSURLConnection alloc] initWithRequest:request delegate:self];
    if (conn)
    {
        receivedData = [[NSMutableData data] retain];
    }
    else
    {
    }
}

- (void)connection:(NSURLConnection *)connection
  didReceiveResponse:(NSURLResponse *)response
{  
    [receivedData setLength:0];
}  

- (void)connection:(NSURLConnection *)connection 
  didReceiveData:(NSData *)data  
{  
    [receivedData appendData:data];
}  

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{  
    if (chatParser)
        [chatParser release];

    if ( messages == nil )
        messages = [[NSMutableArray alloc] init];

    chatParser = [[NSXMLParser alloc] initWithData:receivedData];
    [chatParser setDelegate:self];
    [chatParser parse];

    [receivedData release];

    [messageList reloadData];

    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:
    [self methodSignatureForSelector: @selector(timerCallback)]];
    [invocation setTarget:self];
    [invocation setSelector:@selector(timerCallback)];
    timer = [NSTimer scheduledTimerWithTimeInterval:5.0 
        invocation:invocation repeats:NO];
}

- (void)timerCallback {
    [timer release];
    [self getNewMessages];
}

코드는 getNewMessages 메소드로 시작된다. 이 메소드는 요청을 작성하고 NSURLConnection을 빌드하여 시작한다. 이는 또한 응답 데이터를 보유하는 데이터 버퍼를 작성한다. 세 가지 이벤트 핸들러인 didReceieveResponse, didReceiveData,connectionDidFinishLoading은 모두 데이터 로딩의 다양한 단계들을 처리한다.

데이터로 메시지를 읽고 뽑아내는 XML 구문 분석기를 시작하기 때문에 connectionDidFinishLoading 메소드가 가장 중요하다.

여기에서 마지막 메소드인 timerCallback은 새 메시지의 요청을 시작하는 타이머로 사용된다. 타이머가 꺼지면 getNewMessages 메소드가 호출되며, 이는 프로세스를 다시 시작하여, 제한시간이 초과되었을 때에 메시지 검색 프로세스를 다시 시작하는 새 타이머를 작성하여 마무리된다.

다음 섹션인 리스트 8에서 XML의 구문 분석을 처리한다.


리스트 8. iOSChatClientViewController.m – 메시지 구문 분석하기
- (void)parser:(NSXMLParser *)parser 
didStartElement:(NSString *)elementName 
namespaceURI:(NSString *)namespaceURI 
qualifiedName:(NSString *)qName 
attributes:(NSDictionary *)attributeDict {
    if ( [elementName isEqualToString:@"message"] ) {
        msgAdded = [[attributeDict objectForKey:@"added"] retain];
        msgId = [[attributeDict objectForKey:@"id"] intValue];
        msgUser = [[NSMutableString alloc] init];
        msgText = [[NSMutableString alloc] init];
        inUser = NO;
        inText = NO;
    }
    if ( [elementName isEqualToString:@"user"] ) {
        inUser = YES;
    }
    if ( [elementName isEqualToString:@"text"] ) {
        inText = YES;
    }
}

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
    if ( inUser ) {
        [msgUser appendString:string];
    }
    if ( inText ) {
        [msgText appendString:string];
    }
}

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName 
   namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
    if ( [elementName isEqualToString:@"message"] ) {
        [messages addObject:[NSDictionary dictionaryWithObjectsAndKeys:msgAdded,
            @"added",msgUser,@"user",msgText,@"text",nil]];

        lastId = msgId;

        [msgAdded release];
        [msgUser release];
        [msgText release];
    }
    if ( [elementName isEqualToString:@"user"] ) {
        inUser = NO;
    }
    if ( [elementName isEqualToString:@"text"] ) {
        inText = NO;
    }
}

이 XML 구문 분석기는 SAX 구문 분석을 아는 누구나 익숙해야 한다. 일부 XML을 제공하면 태그가 열린 상태이거나 닫힌 상태일 때, 텍스트가 발견될 때 등등에 다시 호출한다. DOM 기반 구문 분석기라기 보다는 이벤트 기반 구문 분석기이다. 이벤트 구문 분석기는 경량 메모리 공간을 보유하는 장점이 있다. 하지만 약점은 구문 분석 도중에 호스트 오브젝트에 모든 상태가 저장되어야 하기 때문에 사용하기에 약간 더 어렵다.

프로세스는 msgAdded, msgUser, inUser 및 빈 문자열이나 false로 초기화되는 inText와 같이 모든 멤버 변수들로 시작한다. 그러면 각 태그로서 didStartElement 메소드에 시작되어, 코드는 태그 이름을 보고 적절한 inUser 또는 inText 부울을 설정한다. 이로부터 foundCharacters 메소드는 텍스트 데이터를 적절한 문자열로 추가하는 것을 처리한다. didEndElement 메소드는 그러면 <message> 태그의 끝 부분이 발견될 때에 구문 분석된 메시지를 메시지 목록에 추가하여 태그의 마무리를 처리한다.

이제 메시지를 표시하는 일부 코드가 필요하다. 이는 리스트 9에 표시된다.


리스트 9. iOSChatClientViewController.m – 메시지 표시하기
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

- (NSInteger)tableView:(UITableView *)myTableView numberOfRowsInSection:
                                       (NSInteger)section {
    return ( messages == nil ) ? 0 : [messages count];
}


- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:
                                       (NSIndexPath *)indexPath {
    return 75;
}

- (UITableViewCell *)tableView:(UITableView *)myTableView 
   cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = (UITableViewCell *)[self.messageList 
        dequeueReusableCellWithIdentifier:@"ChatListItem"];
    if (cell == nil) {
        NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"ChatListItem" 
            owner:self options:nil];
        cell = (UITableViewCell *)[nib objectAtIndex:0];
    }

    NSDictionary *itemAtIndex = (NSDictionary *)[messages objectAtIndex:indexPath.row];
    UILabel *textLabel = (UILabel *)[cell viewWithTag:1];
    textLabel.text = [itemAtIndex objectForKey:@"text"];
    UILabel *userLabel = (UILabel *)[cell viewWithTag:2];
    userLabel.text = [itemAtIndex objectForKey:@"user"];

    return cell;
}

이는 UITableViewDataSourceUITableViewDelegate 인터페이스로 정의되는 모든 메소드이다. 가장 중요한 것은 cellForRowAtIndexPath 메소드이며, 이는 목록 항목에 대한 사용자 정의 UI를 작성하고 텍스트 필드를 그 메시지에 대한 적절한 텍스트로 설정한다.

이 사용자 정의 목록 항목은 Resource 폴더에 작성해야 하는 새 ChatListItem.xib 파일에 정의된다. 그 파일에서 1과 2로 태그된 두 개의 레이블이 있는 새 UITableViewCell 항목을 작성한다. 다른 모든 코드와 함께 이 파일은 다운로드 가능 프로젝트에 사용할 수 있다(다운로드 참조).

cellForRowAtIndexPath 메소드에서 코드가 이러한 ChatListItem 셀 중 하나를 할당하면, 레이블에 대한 텍스트 필드를 그 메시지에 대해 발견한 텍스트와 사용자 값으로 설정한다.

소화할 내용이 많다는 것은 인정하지만, 이제 거의 다 되었다. 이미 뷰를 시작하고 메시지 XML을 얻어 이를 구문 분석하고 메시지를 표시하는 코드가 있다. 유일하게 남은 작업은 메시지를 전송하는 코드를 쓰는 것이다.

코드 빌드하기의 첫 번째 부분은 사용자 이름의 설정을 작성하는 것이다. iOS 애플리케이션들은 Setting 제어판에 들어가는 사용자 정의 설정을 정의할 수 있다. 설정을 작성하려면 New File 마법사를 사용하여 Resources 폴더에서 설정 번들을 작성해야 한다. 그러면 그림 7의 설정 편집기를 사용하여 하나의 설정만 아래로 삭제한다.


그림 7. 설정 설정하기
설정 편집기의 화면 캡처

그러면 User라는 제목으로 설정을 정하고 키 user_preference를 갖도록 정의한다. 이로부터 리스트 10의 메시지 전송 코드에 대한 사용자 이름을 얻는 이러한 환경 설정을 사용할 수 있다.


리스트 10. iOSChatClientViewController.m – 메시지 전송하기
- (IBAction)sendClicked:(id)sender {
    [messageText resignFirstResponder];
    if ( [messageText.text length] > 0 ) {
        NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

        NSString *url = [NSString stringWithFormat:
            @"http://localhost/chat/add.php"];

        NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] 
            init] autorelease];
        [request setURL:[NSURL URLWithString:url]];
        [request setHTTPMethod:@"POST"];

        NSMutableData *body = [NSMutableData data];
        [body appendData:[[NSString stringWithFormat:@"user=%@&message=%@", 
             [defaults stringForKey:@"user_preference"], 
             messageText.text] dataUsingEncoding:NSUTF8StringEncoding]];
        [request setHTTPBody:body];

        NSHTTPURLResponse *response = nil;
        NSError *error = [[[NSError alloc] init] autorelease];
        [NSURLConnection sendSynchronousRequest:request 
            returningResponse:&response error:&error];

        [self getNewMessages];
    }

    messageText.text = @"";
}

- (void)viewDidLoad {
        [super viewDidLoad];

    messageList.dataSource = self;
    messageList.delegate = self;

    [self getNewMessages];
}

@end

이는 Send Message 단추의 클릭 핸들러 코드이다. 이는 add.php 스크립트의 URL이 있는 NSMutableURLRequest를 작성한다. 그러면 이는 메시지의 본문을 POST 형식으로 인코딩된 사용자와 메시지 데이터가 있는 문자열로 설정한다. 그러면 이는 NSURLConnection을 사용하여 메시지 데이터를 서버로 동시에 전송하고 getNewMessages를 사용하여 메시지 검색을 시작한다.

이 파일의 맨 아래에 있는 viewDidLoad 메소드는 뷰를 로드할 때에 호출되는 것이다. 이는 메시지 검색 프로세스를 시작하고 이 오브젝트로 메시지 목록을 연결하여 메시지 목록에서 데이터를 얻을 장소를 알게 된다.

이렇게 모두 코딩되면 애플리케이션을 테스트할 시간이다. 그러면 그림 8의 Settings 페이지에서 사용자 이름을 설정하여 시작한다.


그림 8. Settings 페이지
General, Safari, Photos 및 iOSChatClient 옵션이 있는 Settings 페이지의 화면 캡처

이로부터 iOSChatClient 애플리케이션을 클릭하면 그림 9의 설정 페이지가 표시된다.


그림 9. 사용자 이름 설정하기
User 필드에 'Megan' 값이 있는 OSChatClient 설정 페이지의 화면 캡처

그러면 독자가 하는 것처럼 전화기에 애플리케이션으로 돌아가서 그림 10과 같이 키보드를 사용하여 메시지를 입력한다.


그림 10. 새 메시지 입력하기
QWERTY 키보드, 메시지 텍스트 상자, Send 단추 및 사용자 Jack으로부터의 텍스트 메시지가 있는 화면 캡처

그 후에 Send 단추를 누르면 그림 11과 같이 메시지가 서버로 이동되고, 게시된 후에 messages.php에서부터 리턴되는 것을 볼 수 있다.


그림 11. 완성된 대화 애플리케이션
메시지 텍스트 상자, Send 단추 및 사용자 Jack과 Megan으로부터 두 개의 테스트 메시지가 있는 화면 캡처

Send 단추와 메시지 목록 사이에 직접 연결이 없음을 코드에서부터 주목하게 될 것이다. 따라서 메시지를 목록으로 만드는 유일한 방법은 서버를 통해 데이터를 데이터베이스에 성공적으로 삽입하는 것이다. 그 후에 message.php 코드는 메시지 목록에 표시하기 위해 메시지를 성공적으로 리턴한다.

결론

물론 소화할 내용이 많지만, 독자는 이 기사에서 많이 배웠다. 백엔드에서 XML로 일부 데이터베이스 작업을 하였다. 데이터를 전송하고 서버에서부터 검색하는 사용자 정의 사용자 인터페이스로 iOS 애플리케이션을 빌드했다. XML 구문 분석기를 사용하여 서버에서부터 응답 XML을 다시 살펴보았다. 그리고 메시지를 세련되게 보이도록 하는 사용자 정의 목록 UI를 빌드했다.

이를 사용하여 다음으로 할 일은 이 글을 읽는 독자에게 달려있다. Apple은 iPhone이나 iPad에서 원하는 대로 모양을 구현하는 도구를 제공하였다. 그리고 이 기사에서는 자체적인 네트워크 사용 앱을 빌드하기 위한 로드맵을 제공하였다. 독자도 이에 뛰어 들어 한 번 시도해보기 바란다. 멋진 결과물을 빌드한다면 필자에게 알려주기 바란다. App Store에서 이를 확인하도록 해줄 것이다.

출처 : http://www.ibm.com/developerworks/kr/library/x-ioschat/index.html