사진과삶2008/10/28 23:00

Posted by 종이비행기
개발과삶2008/10/28 01:50
최근 수신한 메일이 있으면 iPhone, iPod touch 메일 아이콘에 빨간색 동그라미 안에 있는 숫자를 보실 수 있습니다.
최근 수신한 이메일 개수를 보여주기위한 배지(Badge)인데, 최근 수신한 데이터나 최근 등록한 데이터가 있을 때 보여주게 하면 시각효과가 좋습니다.

방법은 아주 간단합니다.

[[UIApplication sharedApplication] setApplicationIconBadgeNumber:1];

이렇게 하면 1이라는 숫자가 표시되고,

[[UIApplication sharedApplication] setApplicationIconBadgeNumber:0];

이렇게 하면 배지는 사라집니다.

App을 종료하기 전에 위 코드를 한 번만 실행해주면 종료후 iPhone 화면에 배지가 달린 아이콘을 보실 수 있습니다.


-- KIDG에 올린 글
Posted by 종이비행기
개발과삶2008/10/24 09:15
HTML 파일을 읽어서 WebView로 출력
    webView.userInteractionEnabled = true;
    NSString *filePath = [[NSBundle mainBundle] pathForResource:@"index" ofType:@"html"]; 
    NSData* htmlData = [NSData dataWithContentsOfFile:filePath]; 
    [webView loadData:htmlData MIMEType:@"text/html" textEncodingName:@"UTF-8" baseURL:[NSURL URLWithString:@"http://www.pcraft.kr/index.html"]];     

WebView 웹사이트 로딩
     webView.userInteractionEnabled = true;
     [webView loadRequest:[[NSURLRequest alloc] initWithURL:[[NSURL alloc] initWithString:@"http://www.google.com"]]];

Posted by 종이비행기
개발과삶2008/10/24 01:54
NSString* aStr = [[NSString alloc] initWithData:aData encoding:NSUTF8StringEncoding];
NSData* aData = [aStr dataUsingEncoding: NSUTF8StringEncoding];
Posted by 종이비행기
개발과삶2008/10/23 21:56
현재 iPhone을 개발하시는 분들은 대부분 해외 시장을 염두에 두고 개발을 하고 계시리라 생각합니다.
결국, 한국어와 영어를 동시에 지원해야하는 과제가 생기겠죠.
iPhone의 로컬라이징에 대한 정보가 많이 없어서 간략하게 정리해볼까 합니다.

1. xib 로컬라이징
xib는 아시다시피 Interface Builder로 만든 UI 인스턴스 입니다.
xcode에서 로컬라이징할 xib를 선택한후 Get Info를 합니다.
General Tab에서 Make Localization을 클릭하면 기본적으로 English가 만들어집니다.
Korean을 추가하려면 Add Localization을 클릭하여 Korean을 입력하면 생성이 됩니다.
이 순간부터 독립적인 UI가 생기므로 개발이 완료된 후 이 작업을 하시는 것이 좋습니다.
이제는 기존 xib파일이 2개로 나뉘어 있는 것을 보실 수 있는데, 그중 English를 더블클릭하여
Interface Builder로 여신후 Tool - Strings로 변경을 하거나 UI를 직접 편집하여
영어로 변역하여 줍니다. 작업이 완료되면 저장하고 Interface Builder를 종료합니다.
에뮬레이터 또는 디바이스에서 언어를 바꿔보시면서 테스트를 하시면 됩니다.


2. 소스코드에서 메시지의 로컬라이징
파일을 하나 만듭니다. Resources 정도의 그룹에서 하시면 되겠습니다.
Add - New File...을 하신후 Mac OSX 항목에 있는 Other의 Strings File을 이용하여 파일을 생성합니다.
이름은 Localizable.strings 으로 합니다.
xib에서 Make Localization 한 것과 같이 동일하게 English, Korean을 추가합니다.
각각의 파일에 소스코드에서 사용되는 메시지를 입력합니다.
입력방법은 식별할 수 있는 코드와 언어별 메시지를 입력합니다.

"Cancel"   = "취소";

위와 같이 ""를 이용하여 식별코드(식별명칭)과 메시지를 입력하고 줄 마지막에는 ;(세미콜론)을 꼭 붙여줍니다.
이런식으로 입력한후 소스코드에서는 NSLocalizedString(@"Cancel", @"취소 버튼") 이렇게 하면 언어별로 메시지를
구분해서 출력해줄 수 있습니다.
NSLocalizedString()의 두번째 파라미터는 소스코드상에 확인을 위한 것일 뿐 전혀 영향을 미치지 않으니
한글로 적절히 그 메시지의 역할을 적어주면 가독성이 떨어지지 않으면서 로컬라이징을 할 수 있으리라 봅니다.


3. App 아이콘 아래의 App 제목의 로컬라이징
에뮬레이터 또는 디바이스에 App을 설치하면 아이콘과함께 App 제목이 출력되는데,
이것도 로컬라이징이 가능합니다.

역시 Resources 그룹에서 Add - New File...을 하신후 2에서 하신 것처럼 Strings File을 하나 만듭니다.
이름은 InfoPlist.strings 입니다. 만드신후

 "CFBundleDisplayName" = "내 프로그램";

와 같이 등록합니다. 물론, English 파일에는 영어권에 맞게 변역해주면 됩니다.
빌드하면 App 이름이 언어설정에 따라 자동으로 맞게 출력되실 것입니다.


-- KIDG에 등록한 글

Posted by 종이비행기
개발과삶2008/10/23 21:55
iPod, iPhone을 보면 iPod라고 쓰여진 또는 안테나가 있는 가장 위의 상태바에
처리중임을 나타내는 아이콘을 출력할 수 있습니다.
간단히 아래 코드를 추가해주기만 하면 됩니다.

[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
물론, NO로 하면 사라집니다. NO 파라미터로 실행할 때까지 계속 돌아갑니다.

-- KIDG에 등록한 글
Posted by 종이비행기
사진과삶2008/10/18 23:00

저작자 표시 비영리 변경 금지
Posted by 종이비행기
개발과삶2008/10/13 00:52
  개발자의 입장에서 정리한 지식을 글로 옮기는 것이라 이론적인 것보다는 실제 동작하는 코드를 바탕으로 글을 쓰고 있습니다. 부족한 부분이 있더라도 이점 양해를 부탁드리겠습니다.


   웹사이트의 RSS를 수집하거나 웹2.0 사이트들이 제공하는 Open API를 이용하여 개발하려면 HTTP/HTTPS와 같이 널리 알려진 송수신 프로토콜을 이용하게 되는데, iPhone 역시 고수준의 API를 제공하기 때문에 일반적인 경우에는 BSD Socket을 이용하여 저수준의 입출력을 할 필요는 없다. 즉, NSURLRequest나 NSMutableURLRequest를 이용하여 헤더, 쿠키를 지원하면서 HTTP/HTTPS 통신을 손쉽게 할 수 있다.

   HTTP 프로토콜은 Request를 하고 Response를 받는 형태로 서버와 클라이언트 간의 정보를 교환하는 프로토콜이다. iPhone의 API에서도 서버에 데이터를 요청하기 위해 NSURLRequest(또는 NSMutableURLRequest)를 초기화를 하고 이를 NSURLConnection를 경유하여 전송하고 NSURLResponse로 서버가 송신하는 헤더를 받아오고 NSURLConnection의 delegate 메소드로 결과 데이터나 에러처리를 하게 된다.

  더 자세한 내용은 Apple에서 제공하는 URL Loading System Guide를 참고하고 간단한 예제를 만들면서 코드가 어떻게 실행이 되는지 살펴보겠다.

// url 문자열을 이용하여 HTTP로 웹사이트에 접속
- (BOOL)requestUrl:(NSString *)url {
// URL 접속 초기화
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]
                                                                                                         cachePolicy:NSURLRequestUseProtocolCachePolicy
                                                                                                    timeoutInterval:15.0];

// GET 방식
[request setHTTPMethod:@"GET"];

// POST 방식은
// [request setHTTPMethod:@"POST"]; // POST로 선언하고
// [request setHTTPBody:[bodyString dataUsingEncoding:NSUTF8StringEncoding]]; // 전송할 데이터를 변수명=값&변수명=값 형태의 문자열로 등록

// 헤더  추가가 필요하면 아래 메소드를 이용
// [request setValue:value forHTTPHeaderField:key];

NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
if (connection) {
    self.receivedData = [[NSMutableData data] retain]; // 수신할 데이터를 받을 공간을 마련
    return YES;
}

return NO;
}

   위의 메소드를 호출하면 비동기로 통신이 되기 때문에 접속만 이상이 없다면 호출 즉시 YES가 반환된다. 현 상태에서는 결과 데이터를 받을 수는 없다. 비동기 통신이라면 결국 콜백함수를 통해 수신된 데이터가 발생할 때 수신 데이터를 처리할 수 있다. 그렇다면, 콜백함수를 알아보겠다. 물론, Cocoa에서는 델리게이트 메소드라는 용어가 맞겠다.

  Cocoa에서 제공하는 NSURLConnection 관련 주요 델리게이트 메소드는 아래와 같다. 물론, 이 외에도 몇 개가 더 존재하나 기본적으로 아래의 것만 구현해도 개발하는 데 큰 문제는 없었다.

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)aResponse {
[receivedData setLength:0];
self.response = aResponse;
}
   이 메소드가 호출되는 시점은 서버로의 요청에 대한 반응이라 보면 되겠다. NSURLResponse가 반환되는데 이 과정에서 서버가 클라이언트에 보내는 헤더 정보를 미리 받아볼 수 있다. 이 의미는 앞으로 가져오게될 컨텐츠의 종류(mime type)과 문자셋(char-set)을 미리 확인하고 후에 데이터를 모두 받으면 적절한 디코딩(decode)을 할 수 있도록 하는 데 있다. 예를들어, 서버측에서 UTF-8로 발신을 했는데, 클라이언트측에서는 EUC-KR로 해석하려고 한다면 깨진 데이터만 얻을 뿐이다. 또한, 서버에서 보내는 데이터가 이미지 데이터라면 이미지로 해석하지 않는다면 쓸모없는 데이터가 될 것이다.
   수신되는 데이터는 NSMutableData인 receivedData에 넣게 되는데 여기서는 데이터를 수신받을 준비가 끝났으니 초기화하라는 이야기이다. 또한, 현재 NSURLResponse를 데이터 수신후에 이용해야하기 때문에 인스턴스 변수로 임시 저장한다(self.response = aResponse). NSMutableData의 메모리 할당은 requestUrl 메소드에서 이미 하였다.  

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[receivedData appendData:data];
}
   네트워크 상의 데이터는 한 번에 모든 데이터가 전송됨을 보장받을 수 없다. 그래서 수신이 완료될 때까지 지속적으로 받아와야 하는 데, 이 메소드가 그 역할을 한다. 수신되는 데이터가 있을 때마다 receivedData에 추가하는 것이 그것이다.

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLog(@"Error : ", [error localizedDescription]);
}
   데이터가 전송되다가 네트워크 장애와 같은 에러가 발생할 수 있다. 그런 에러가 발생하면 위의 메소드가 호출이 된다. 위 메소드를 이용하여 에러처리를 할 수 있다. 자원을 해제하고 경고창을 띄운후 루틴을 종료하는 처리를 하면 된다.

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
data = [[NSString alloc] initWithData:receivedData encoding:NSUTF8StringEncoding];
}
   데이터를 모두 수신하게되면 이 메소드가 호출되는데 여기서는 수신한 NSMutableData를 적절한 형태의 데이터로 변환하면 된다. 여기서는 HTML 웹페이지를 수신하려 하므로 NSString으로 변환한다. 물론, 문자셋은 헤더로 부터 수신한 문자셋을 참조하여 변환하면 된다. 여기서는 UTF-8로 변환하게 되는데, 국내 사이트의 경우에는 대부분 EUC-KR 일 것이다. 그러나 Apple에서 제공하는 어떠한 문서를 찾아봐도 EUC-KR 에 대한 상수값을 찾을 수 없었다. NSUTF8StringEncoding 대신 -2147481280 를 입력하면 국내 사이트도 정상적으로 볼 수 있을 것이다. 인코딩 상수값에 대한 테이블은 http://limechat.net/rubycocoa/wiki/?NSStringEncoding 여기를 참조하기 바란다. 참고로, 일본어 문자셋 변환은 Apple 문서에서 찾을 수 있었다.

   추가로 위에서 설명하지 않은 POST 방식과 헤더를 추가해서 전송하는 방법을 설명한 후 마치도록 하겠다. POST 방식의 요청은 GET 과 비슷하나 URL과 함께 key=value에 기반한 데이터도 함께 전송한다는 차이점이 있다.  POST 방식은 [request setHTTPMethod:@"POST"]; 로 초기화하고 [request setHTTPBody:[bodyString dataUsingEncoding:NSUTF8StringEncoding]]; 으로 전송할 데이터를 입력하는데 전송할 데이터(여기서는 bodyString이라는 NSString)는 변수명=값&변수명=값 형태의 문자열로 구성해야한다. 물론 값은 기본적으로 urlencode 처리를 해야한다. 헤더는 [request setValue:value forHTTPHeaderField:key]; 와 같이 key에 대한 값을 필요한 개수만큼 추가하면 된다.

   지금까지 간략하게 설명을 했으나 부족한 것이 많을 것이다. 힌트 정도만 보고 찾아서 직접 코딩해보는 것이 더 도움이 된다고 생각해서이기도 하지만 상세한 튜터리얼을 만들 시간이 부족한 이유가 더 크다. URL Loading System Guide에 더 자세한 설명이 있으니 꼭 참조하기를 바란다. 참고로, 동기 전송으로도 통신을 처리할 수 있으나 UI가 동작하는 쓰레드에서는 사용할 수 없었다.


-- KIDG에 등록한 글
Posted by 종이비행기
개발과삶2008/10/05 18:12
  본 튜터리얼은 사내 직원 교육용으로 만든 것으로 초급 자바 개발자들이 쉽게 iBATIS를 이용하여 개발하도록 하여 좀 더 나은 품질의 코드와 제품을 생산할 수 있도록 하기 위한 바램으로 작성한 자료이다. 즉, 고급 기술 및 상세 기능은 배제를 하였음을 미리 밝힌다.

8. SqlMap에서의 데이터 조회
  데이터를 입력을 해봤으니 입력된 데이터를 출력할 수 있도록 조회용 코드를 작성하도록 하겠다. 조회는 일반적으로 1건 조회와 여러건 조회로 나뉠 수 있는데, 여러건 조회는 페이징 문제도 포함하고 있어 1건 조회에 비해 다소 복잡하다 하겠다.

  먼저, 입력된 사원 1명의 정보를 조회하는 기능을 구현해보고 1건 이상의 조회하는 기능을 구현해 보도록 한다.

  1건 조회는 경우에 따라 필수 컬럼만 조회 컬럼으로 지정할 수 있지만 지금은 컬럼의 수가 많지 않고 모두 필수 컬럼에 속하므로 전체를 조회하는 SQL을 구현한다. 1건을 조회한다는 의미는 고유 번호(일련번호, 주민등록번호...)로 조회한다고 보면 되겠다. 여기서는 사원 테이블이므로 PK인 사원번호(emp_no)를 대상으로 조회하겠다.

SELECT emp_no, emp_name, hire_date, dept_no
FROM emp
WHERE emp_no=?

  위 SQL은 emp 테이블을 조회하는 JDBC에서 사용했던 쿼리이다. 이를 iBATIS의 SqlMap에 넣으려면 다음과 같이 작성하면 된다.

<!-- 사원테이블에 사원 정보 1건 조회 -->
<select id="findByPrimaryKey" parameterClass="int" resultClass="ibatis.sample01.model.Emp">
SELECT emp_no AS empNo, emp_name AS empName, hire_date AS hireDate, dept_no AS deptNo
FROM emp
WHERE emp_no=#value#
</select>

  파라미터 값이  #value#로 바뀌는 것 이외에는 차이가 없다. 여기서 조회되는 정보는 Emp 클래스로 매핑되어 결과를 얻게될 것이다. 위 SqlMap 요소를 지난 번에 생성한  emp.xml에 추가하면 된다. SqlMap 작성시 parameterClass와 resultClass는 주의깊게 작성해야 한다. 여기서 잘못 작성하면 디버깅하기가 곤란해지는 상황이 오기도 한다.  JUNIT 또는 간단한 테스트 코드를 이용하여 CRUD를 넣을 때마다 테스트 해보는 것이 추후 디버깅 시간을 줄일 수 있을 것이다.

  이제는 SqlMap 설정을 이용하는 웹인터페이스와 컨트롤러를 작성한다.

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
    <form method="post" action="select_emp.jsp">
    <p>사원번호: <input type="text" name="emp_no" /></p>
    <p><input type="submit" value="전송" /></p>
    </form>
</body>
</html>


<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@page import="java.io.Reader"%>
<%@page import="ibatis.sample01.model.Emp"%>
<%@page import="com.ibatis.sqlmap.client.SqlMapClientBuilder"%>
<%@page import="java.io.IOException"%>
<%@page import="com.ibatis.sqlmap.client.SqlMapClient"%>
<%@page import="com.ibatis.common.resources.Resources"%>
<%
SqlMapClient sqlMapClient = null;

Reader reader = Resources.getResourceAsReader("ibatis/sample01/sqlmap/SqlMapConfig.xml");
sqlMapClient = SqlMapClientBuilder.buildSqlMapClient(reader);
reader.close();

request.setCharacterEncoding("UTF-8");

String empName = request.getParameter("name");

int empNo = Integer.parseInt(request.getParameter("emp_no"));

Emp emp = (Emp)sqlMapClient.select("selectEmp", new Integer(empNo));
%>
사원번호:<%=emp.empNo%><br />
사원명:<%=emp.empName%><br />

  예를들기 위한 예제일 뿐이며 실무에서 이런 인터페이스가 필요할 경우는 거의 없을 것이다. 단, pk로 데이터를 요청하는 루틴은 많이 사용되므로 PK를 이용한 조회는 미리 구현해두는 것이 좋겠다.


Posted by 종이비행기
사진과삶2008/10/04 09:14
어느날 갑자기 여기 지구의 생명으로 탄생하고 살아가다 다시 지구로 산화하는 존재. 그 존재에서 외로움을 느낍니다.
그 외로움을 감추려고 사회적 존재가 되려고 노력은 하지만 결국은 혼자일 뿐입니다.
자기가 믿는 바를 믿고 주변의 어지러운 상황에 연연하지 않는다면 본인의 의지로 죽음의 길은 가지 않을 지 모릅니다.
자신을 진정 사랑하는 사람은 어느 누구도 아닌 바로 나 자신입니다.

고인이 되신 최진실씨를 추모하며...





Posted by 종이비행기