- 원본 비디오 시청: https://delphicon.embarcadero.com/talks/real-world-codesite-logging-techniques-1/
- DelphiCon 전체 보기 (현재 무료, 향후 유료 전환 예상): https://delphicon.embarcadero.com/replays/
- 데브기어의 DelphiCon 소개 페이지로 가기: https://devgear.co.kr/archives/3692
코드사이트 로깅 실전 활용 기법 (Real-world CodeSite Logging Techniques) 를 요약했습니다. (이 요약 번역은 원본 비디오와 내용이 일부 다르거나, Q&A등 일부 생략되었을 수 있습니다.)
실전에서 바로 활용할 수 있도록 코드사이트(CodeSite)의 로깅 기술 중 핵심적인 것을 뽑아서 설명합니다. (코드사이트 무료 에디션은 델파이의 겟잇 패키지 매니저에서 무료로 받을 수 있습니다.)
- 코드사이트(CodeSite) 개요: Raize에서 만든 로깅 도구 개요
- (데모) 겟잇에서 코드 사이트 익스프레스 무료 다운로드
- CodeSite 도구들
- (데모) CodeSite 도구 메뉴 위치
- (데모) CodeSite 폴더 살펴보기
- (데모) CSDispatcher.exe를 윈도우 서비스로 설치하기 (07분07초부터)
- (데모) CSContoller.exe를 통해 디스패처를 수작업으로 시작/종료하거나 설정하기 (07분29초부터)
- (데모) 고객용 샘플앱을 통해 로깅 살펴보기 (08분26초부터)
- (데모) Method Tracer 사용하여 오류 위치를 쉽게 찾기 (11분22초부터)
- 디스패처 (CodeSite Dispatcher)
- (데모) 원격 로깅 설정 (15분46초부터)
- CodeSite.Send 메소드의 메시지 유형
- (데모) CodeSite.Send 메소드의 메시지 유형 활용하기 (19분09초부터)
- (데모) 너무 큰 데이터세트가 로깅되는 것을 방지하기 (22분58초부터)
- 스크래치패드 (CodeSite ScratchPad)
- (데모) CodeSite ScratchPad에서 메모리 누수 파악하기 (24분54초부터)
- CodeSite 로그 목적지 지정
- (데모) DestinationString 직접 작성하기 (29분40초부터)
- (데모) DestinationStringBuilder 사용하기 (34분25초부터)
- CodeSite에서 Logger 여러개 사용하기
- (데모) 하나의 앱에 CodeSite 로거 2개를 사용하기 (38분40초부터)
- CodeSite 로거 활성화를 활용한 실전 팁
- (데모) 평소에는 오류 정보만 로깅하다가 꼭 필요할 때에 전체 로깅하기 (45분05초부터)
- CodeSite의 OnSendMsg로 메시지 가로채기와 다루기
- (데모) OnSendMsg로 메시지 가로채기와 다루기 (49분19초부터)
- 세션에서 소개한 코드사이트 로깅 테크닉 요약
발표자 (Bob Swart)는 Dr. Bob으로 잘 알려진 델파이 개발자이자 컨설선트입니다.
- Dr. Bob의블로그: drbob42.com
원본 비디오 시청: https://delphicon.embarcadero.com/talks/real-world-codesite-logging-techniques-1/
코드사이트(CodeSite) 개요: Raize의 로깅 도구 개요
- 에디션
- 코드사이트 익스프레스: 무료, 겟잇패키지매니저에서 다운로드
- 코드사이트 스튜디오: 유료, www.raize.com에서 구입
- 로그 표현 방식
- 라이브 로깅
- 파일 로깅
- 로그 저장 위치
- 로컬 로깅
- 원격 로깅 (스튜디오 에디션 Only, 배포한 앱에서 로그를 원격의 로그 저장소로 보내도록 함)
- 로깅 솔루션으로서 제공되는 기능
- 앱 사용자는 어떤 로그가 얼마나 수집되는 지를 신경쓰지 않아도 됨
- 로그 파일 분석 도구 제공됨
(데모) 겟잇에서 (무료 에디션인) 코드 사이트 익스프레스 무료 다운로드
Delphi > Tools > GetIt Package Manager 선택 > 겟잇 필터에서 ‘Code’라고 입력 > CodeSite Express를 선택하고 [Install] 버튼 클릭 후 기본 설정을 따라 설치 > 델파이 재시작 후 겟잇에서 Installed로 표시되는 지 확인
(그림1. 겟잇에서 CodeSite를 찾아서 설치하기)
CodeSite 도구들
- 로깅 도구
- CSDispatcher.exe: 앱에서 발생한 로그를 가져와서 저장하는 도구 (윈도우 서비스로 작동하면 자동으로 시작/종료되므로 편함)
- CSContoller.exe: CSDispatcher를 시작/종료 하거나 설정하는 도구
- 조회 도구
- CSFileViewer.exe: 파일로 저장된 로그를 조회하는 도구
- CSLiveViewer.exe: 로그가 전달되면 바로 보여주는 도구 (매우 유용함)
- 기타 도구
- CSDestStringBuilder.exe: 로그 저장소 설정을 선택하면 해당 문자열이 생성됨
- CSFileExporter.exe: 로그 파일을 XML형식으로 내보내기
- CSFileSplitter.exe: 큰 로그 파일을 지정된 파일 크기의 작은 로그 파일들로 쪼개기
- CSMergeFiles.exe: 작은 로그 파일들을 하나로 병합하기
(데모) CodeSite 도구들
- Delphi > Tools > CodeSite > 하위 메뉴로 각 도구들이 표시됨
- (예를 들어) Delphi > Tools > CodeSite > CodeSite Method Tracer를 사용하면,
메소드 진입과 메소트 통과를 로깅하도록 하는 코드를 쉽게 추가할 수 있음
(데모) CodeSite 폴더 살펴보기
코드사이트 폴더 (기본 위치는 Program Files (x86) > Raize > CS5
- Bin 폴더: 설치된 앱이 있는 곳으로서 CodeSite의 모든 도구들의 실행 파일이 있는 곳
- Tool 폴더: CS5_Tools.exe가 있는 곳
- CS5_Tools.exe를 사용하면, 고객의 컴퓨터에도 디스패처, 뷰어 등의 도구를 설치할 수 있다.
- 내 경우 고객의 컴퓨터에는 로컬 로깅일 경우 대체로 ‘디스패처’만 설치한다. 디스패처는 ‘윈도우 서비스’로 작동하도록 설치하여서 고객이 로그와 관련하여 크게 신경쓰지 않도록 한다. (원격 로깅의 경우에는 고객의 컴퓨터에 디스패처도 설치할 필요가 없다)
(데모) CSDispatcher.exe를 윈도우 서비스로 설치하기 (7분7초부터)
- 명령창 C:\Program Files (x86)\Raize\CS5\Bin 위치에서 CSDispatcher.exe / install 을 입력하고 엔터키를 치면, Service installed successfully 메시지 창이 표시됨
- C:\Program Files (x86)\Raize\CS5\Bin>CSDispatcher.exe / install
- 위와 같이 설치하면, 로그를 수작업으로 시작하거나 종료할 필요가 없음
(데모) CSContoller.exe를 통해 디스패처를 수작업으로 시작/종료하거나 설정하기 (7분29초부터)
- 이미 디스패처가 윈도우 서비스로 설치되었다면 제거한다.
- CSContoller.exe를 관리자 계정으로 실행 (Run as Administrator)
(데모) 고객용 샘플앱을 통해 로깅 살펴보기 (8분26초부터)
아래와 같이 로깅 코드를 넣으면, 코드사이트로 SQL 구문이 오류 정보와 함께 전달되므로, SQL 구문으로 인해 발생된 오류임음을 쉽게 파악할 수 있음
uses
CodeSiteLogging;
…
procedure …
begin
FDQuery1.Close;
FDQuery1.SQL.Text := ‘SELECT * FROM Customers’+
‘WHERE Country = ‘’’+ cbCountry.Items[cbCountry.ItemIndex] + ‘’’’;
try
FDQuery1.Open;
except
on E: Exception do
CodeSite.SendException(FDQuery1.SQL.Text, E)
end;
end;
(데모) Method Tracer 사용하여 오류 위치를 쉽게 찾기 (11분22초부터)
- 원하는 메소드를 선택하고 Trace Method, $IFDEF 등을 지정하면 해당 위치에 로깅 코드가 들어간다.
- $IFDEF는 DEBUG가 기본 설정이지만, 원한다면 RELEASE 등을 설정할 수도 있다.
(그림2. 특정 메소드 내 오류 발생 유무를 한눈에 파악할 수 있어서 오류가 난 지점을 쉽게 파악할 수 있다.)
디스패처 (CodeSite Dispatcher)
- 얼마든지 무료로 배포할 수 있다.
- CS5_Tools.exe: 고객 컴퓨터에 로컬 로깅 (로컬에 로그를 남김)을 하기 위해 디스패처 등을 설치할 사용
- 윈도우 서비스로 설치: CSDispatcher.exe / install
- ConnectUsingTCP 옵션: 일반적인 로컬 로깅이 안될 때 또는 원격로깅을 할 때 선택
- ISAPI DLL들이 포함되어서 서비스로 작동
- 기본 포트: TCP 3434 또는 UDP 3435
- 원격 로깅 시에는, ConnectUsingTCP(디스패처가 작동하는 원격 IP주소)
- 고객의 컴퓨터에 디스패처를 설치할 필요없음
- 고객의 앱에 코드사이트 로깅 코드가 들어 있기만 하면 됨
(데모) 원격 로깅 설정 (15분46초부터)
프로젝트 파일에서 Application.Initialize 아래에 코드 2줄을 추가한다.
program…
uses
CodeSiteLogging,
..
begin
Application.Initialize;
CodeSite.Enabled := True;
CodeSite.ConnectUsingTcp(192.168.1.19’);
…
end.
그 결과
- 원격의 로그 서버에서 해당 로그를 볼 수 있다.
- 고객 컴퓨터는 코드에서 지정된 대로 로그를 보내기만 하므로 아무것도 설치할 필요가 없다.
- 로그 서버를 별로로 두고, 각 고객의 컴퓨터에서 보내온 로그를 각 컴퓨터 별로 관리하면, 로그 파악을 위해 고객과 연락할 필요가 없다.
CodeSite.Send 메소드의 메시지 유형
- csmYellow, csmGreen, csmOrange, csmBlue, csmRed,…
- 각 색상별로 특정 유형이 지정되도록 하면 (특히 팀 프로젝트에서) 매우 유용하다.
- 예시: 녹색(SQL문장), 노랑(결과), 파랑(SOAP 또는 REST 호출), 주황(XML 또는 JSON), 빨강(200 OK가 아닌 모든 Response) …
- csmInfo, csmWarning, csmError
- csmDataSet (CodeSiteDBTools 유닛 사용 시)
(데모) CodeSite.Send 메소드의 메시지 유형 활용하기 (19분09초부터)
uses
CodeSiteLogging;
CodeSiteDBTools; //csmDataSet 사용을 위함
…
procedure …
begin
{$IFDEF DEBUG}CodeSite.TraceMethod(Self, ‘Button1Click’);{$ENDIF}
FDQuery1.Close;
FDQuery1.SQL.Text := ‘SELECT * FROM Customers’+
‘WHERE Country = ‘’’+ cbCountry.Items[cbCountry.ItemIndex] + ‘’’’;
try
// SQL 구문에는 녹색 표시 (그림3)
CodeSite.Send(scmGreen, FDQuery1.SQL.Text);
FDQuery1.Open;
// 결과 데이터의 갯수에는 노랑색 표시 (그림3)
CodeSite.Send(scmYellow, FDQuery1.RecordCount.ToString + ‘ 개 데이터’);
// 결과 데이터세트를 통채로 전달 (그림4)
CodeSite.Send(csmDataSet, ‘Customers’, FDQuery1);
except
on E: Exception do
CodeSite.SendException(FDQuery1.SQL.Text, E)
end;
end;
(그림3. 녹색에는 SQL 구문이, 노랑색에는 해당 결과 데이터의 갯수가 표시된다. 그리고 로그 2개를 선택하면 좌측 하단에 두 로그 간의 시간 차이가 표시되므로, 수행 시간도 파악할 수 있다.)
(그림4. csmDataSet을 사용하면 결과 데이터세트를 볼 수 있다. 주의! 너무 큰 데이터세트를 로그로 받지 않도록 하자)
(데모) 너무 큰 데이터세트가 로깅되는 것을 방지하기 (22분58초부터)
// (변경전)
CodeSite.Send(csmDataSet, ‘Customers’, FDQuery1);
// (변경후, 그림5)
If FDQuery1.RecordCount > 5 then
CodeSite.SendWarning(‘데이터가 5개를 넘음’)
else
CodeSite.Send(csmDataSet, ‘Customers’, FDQuery1);
(그림5. 결과 데이터가 5개 초과이므로 데이터는 남기지 않고, 지정된 메시지만 남긴다. 이 때 SendWarning 메소드를 사용했으므로, 해당 메시지에 느낌표 표시가 붙는다.)
스크래치패드 (CodeSite ScratchPad)
- (유료인) 스튜디오 에디션에 있는 기능
- 라이브 뷰어에 지정한 정보가 지정된 주기에 따라 실시간 표시되며 로그 파일로 남지는 않는다.
- 메모리 점유, 사용자 수 등 원하는 모든 문자열 정보를 실시간으로 볼 수 있다.
(데모) CodeSite ScratchPad에서 메모리 누수 파악하기 (24분54초부터)
procedure …
var
S: TStringList;
begin
S:= TStringList.Create;
S.LoadFromFile(‘C:\temp\verybigfile.txt’);
// Free 하지 않았으므로 한번 실행될 때 마다 16.6MB 메모리 누수가 발생한다.
end;
// [메모리 누수를 라이브 뷰어에 보내는 코드]
// 먼저 Timer 콘트롤을 추가하고 Interval을 2초로 주고 Timer 메소드에 아래 코드를 쓴다.
procedure TFrom42.Timer1Timer(Sender: Object);
begin
CodeSite.Send(csmScratchPad, TimeToStr(now) + ‘ 메모리 사용: ‘ +
(CurrentProcessMemory div (1024 * 1024).ToString + ‘ MB’); //CurrentProcessMemory 함수 설명은 생략
end;
고객의 컴퓨터의 (메모리 등) 자원 현황을 실시간으로 파악하고 재부팅 등 필요한 결정을 할 수 있다.
(그림6. 라이브뷰어의 스크래치패드 창을 열면 코드에 적힌 대로 현재 메모리 사용량이 표시된다.)
CodeSite 로그 목적지 지정
- 뷰어
- Enabled 여부만 지정하면 됨
- 로그 파일
- 모든 에디션: FilePath, FileName, MaxSize, MaxParts
- 스튜디오 에디션에만: LogByDate, LogByDateFormat, Compressed
- DestinationStringBuilder: 설정을 하나의 문자열로 생성
(데모) DestinationString 직접 작성하기 (29분40초부터)
(프로젝트 파일에서)
program…
uses
CodeSiteLogging,
..
var
Destination: TCodeSiteDestination;
begin
Application.Initialize;
Destination := TCodeSiteDestination.Create(CodeSite);
with Destination.LogFile do
begin
FilePath := ‘c:\tmp’; // C드라이브 경로에 로그 파일이 생성
FileName := ‘DelphiCon2020.csl’;
SetLogbyDate(True); // 일별로 로그 파일이 생성
MaxSize := 2000;
MaxParts := 1000;
Active := True;
end;
Destination.Viewer.Active := False; // 라이브뷰어는 일단 끈다.
CodeSite.Destination := Destination;
CodeSite.Enabled := True; // 로깅은 작동하도록 켠다
CodeSite.ConnectUsingTcp(192.168.1.19’); //원격 장비로 셋팅되었으므로, 원격의 C드라이브에 로그 파일이 생성됨
CodeSite.Send(‘델파이콘 2020 앱이 로딩됨’); //앱이 로딩되었음을 로그로 남긴다.
…
end.
(그림7. 로그 파일을 클릭하면 파일 뷰어가 실행되며 로그를 볼 수 있다. 파일 뷰어는 라이브뷰어와 보는 방식이 같지만 스크래치패드가 없다는 점이 다르다)
- 로그 파일이 클라이언트인 로컬 장비에 저장되는 것이아니라 원격 로그 서버에 저장되도록 하면 로그 관리가 중앙화되고 더 유용하다.
(데모) DestinationStringBuilder 사용하기 (34분25초부터)
DestinationStringBuilder를 통해 생성된 문자열을 넣으면 수작업으로 설정 코드를 넣을 필요가 없다.
(그림8. DestinationStringBuilder를 통해 원하는 설정이 모두 담긴 문자열 하나를 만들 수 있다)
HTTP로 연결할 수도 있지만, TCP 포트가 허용된다면 굳이 HTTP로 웹서버에 연결할 필요까지는 없다.
// (변경 전)
with Destination.LogFile do
begin
FilePath := ‘c:\tmp’; // C드라이브 경로에 로그 파일이 생성
FileName := ‘DelphiCon2020.csl’;
SetLogbyDate(True); // 일별로 로그 파일이 생성
MaxSize := 2000;
MaxParts := 1000;
Active := True;
end;
// (변경 후)
Destination.AsString := ‘[생성된 문자열을 여기에 붙여넣는다]’;
CodeSite에서 Logger 여러개 사용하기
- 여러 로거를 사용할 수 있다
- 예: CodeSiteEx를 만들어서 에러와 익셉션인 경우에만 로그를 남기는 역할을 맡긴다 (데모 참조)
- 각 로거 별로 TCodeSiteDestination을 이용하여 로그 위치를 분리할 수 있다.
- Errors.csl로 남기거나,
- 라이브뷰어 (예: “알람 설정, 스크래치패드와 함께 사용)에 남기거나, 등
(데모) 하나의 앱에 CodeSite 로거 2개를 사용하기 (38분40초부터)
// [CodeSiteEX]라는 로거를 폼 변수로 하나 만들고, 이것을 Except 구문 안에서 사용하기
// 1/2 폼 코드에서
var
CodeSiteEx: TCodeSiteLogger; // 폼의 변수로 로거를 선언
…
Initialization // 폼의 Initialization 블록을 사용하여 로거
CodeSiteEx := TCodeSiteLogger.Create(nil); // (finalization 블록에서) 직접 Free 하기로 한다
CodeSiteEx.Destination := TCodeSiteDestination.Create(CodeSiteEx); // CodeSiteEx 소멸시, 해당 Destination 오브젝트도 소멸
CodeSiteEx.Desination.AsString := ‘…..’; // 이때 로그 파일 명은 Errors.csl 로 지정하자.
finalisation
CodeSiteEx.Free;
end.
// 2/2 try-excpt 구문 안에서 CodeSiteEx가 작동하도록 하자.
try
…
except
on E: Exception do
begin
CodeSiteEx.SendException(FDQuery1.SQL.Text, E); // Error.csl에 따로 또 로그를 남기자.
CodeSite.SendException(FDQuery1.SQL.Text, E); // 기존에 있던 구문도 유지하여 함께 작동하도록해도 관계 없다.
end;
CodeSite 로거 활성화를 활용한 실전 팁
- (과도한 로그 수집을 피하기 위해 기본 설정인) 일반 로깅은 비활성화 하자.
- 대신, 오류 또는 익셉션만을 로깅하는 CodeSiteEx를 따로 만들고 평소에는 이것만 작동시키자
- 오류가 발견되고 재현이 어려운 상황이 될 때, 일반 로깅을 활성화하자.
- 각 단계가 로깅 (Enter/ExitMethod)될 수 있도록 일반 로거를 설정하자.
- 이때, 사용자가 직접 로그 수집을 켜고 끌 수 있도록 메뉴로 추가하자.
- 로그 수집 여부에 따라 화면 배경색을 다르게 하는 등 쉽게 파악되도록 하자.
- 기타 필요한 정보를 메시지도 일반 로거에 담아서 추가하자
(데모) 평소에는 오류 정보만 로깅하다가 꼭 필요할 때에 전체 로깅하기 (45분05초부터)
배포하는 앱의 메뉴에 ‘로그 수집’이라는 메뉴를 만들고 그 아래에 켜기와 끄기 메뉴를 넣는다.
// 켜기 메뉴 선택 시 코드
procedure …
begin
CodeSite.Enabled := True;
CodeSite.AddSeparator; // 분리선 추가
CodeSite.Send(‘사용자가 코드사이트 로그를 켬’);
end;
// 끄기 메뉴 선택 시 코드
procedure …
begin
CodeSite.Enabled := False;
end;
// 프로젝트 파일에서는 CodeSite.Enabled := False; 로 설정하여 앱 작동 시 일반 로그 수집은 하지 않도록 한다.
(그림9. 사용자가 직접 로그 수집을 켜고 끄도록 한다.)
CodeSite의 OnSendMsg로 메시지 가로채기와 다루기
- (유료인) 스튜디오 에디션에만 있음
- 오류 횟수 남기기 등 필요한 모든 조치 가능
TCodeSiteSendMsgEvent = procedure ( Sender: TObject;
MsgData: TCodeSiteMsgData; var Handled: Boolean ) of object;
(데모) OnSendMsg로 메시지 가로채기와 다루기 (49분19초부터)
- (이벤트 핸들러를 만들어야 하므로) CodeSiteLogging 유닛은 인터페이스 uses절에 있어야 한다.
- 이벤트 핸들러 프로시저를 만든다.(아래 코드 참조)
- 타이머를 이용하여 스크래치패드에서 모니터리 되도록 한다.(아래 코드 참조)
- FormCreate와 FormDestroy에서 이벤트를 이벤트 핸들러에 연결한다. (아래 코드 참조)
procesure TForm42.CodeSiteSendMsgEvent ( Sender: Object;
MsgData: TCodeSiteMsgData; var Handled: Boolean);
begin
if MsgData.MsgType = csmException then
Inc(Exceptions); //Exceptions는 폼 변수이며 Integer 타입
else
if MsgData.MsgType = csmError then
Inc(Errors); //Errors는 폼 변수이며 Integer 타입
Handled := False; //이벤트가 계속 전달되도록 한다
end;
procedure TFrom42.Timer1Timer(Sender: Object);
begin
CodeSiteEx.Send(csmScratchPad, TimeToStr(now) +….
end;
procedure TFrom42.FormCreate(Sender: Object);
begin
CodeSiteEx.OnSendMsg := Self.CodeSiteSendMsgEvent;
end;
procedure TFrom42.FormDestroy(Sender: Object);
begin
CodeSiteEx.OnSendMsg := nil;
end;
세션에서 소개한 코드사이트 로깅 테크닉 요약
- CodeSite Dispatcher
- (스튜디오 에디션 전용) 원격 로깅
- 메시지 유형들
- (스튜디오 에디션 전용) ScratchPad
- CodeSite Destination들
- 로거 여러개 사용하기
- 로거 켜기와 끄기
- (스튜디오 에디션 전용) CodeSite OnSendMsg
- 원본 비디오 시청: https://delphicon.embarcadero.com/talks/real-world-codesite-logging-techniques-1/
- DelphiCon 전체 보기 (현재 무료, 향후 유료 전환 예상): https://delphicon.embarcadero.com/replays/
- 데브기어의 DelphiCon 소개 페이지로 가기: https://devgear.co.kr/archives/3692
댓글 0
번호 | 제목 | 글쓴이 | 날짜 | 조회 수 |
---|---|---|---|---|
» | [DelphiCon 요약] 코드사이트 로깅 실전 활용 기법 (Real-world CodeSite Logging Techniques) | 관리자 | 2021.01.19 | 22115 |
공지 | [UX Summit 요약] 오른쪽 클릭은 옳다 (Right Click is Right) | 관리자 | 2020.11.16 | 20658 |
공지 | [10.4 시드니] What's NEW! 신기능 자세히 보기 | 관리자 | 2020.05.27 | 22701 |
공지 | RAD스튜디오(델파이,C++빌더) - 고객 사례 목록 | 관리자 | 2018.10.23 | 28461 |
공지 | [데브기어 컨설팅] 모바일 앱 & 업그레이드 마이그레이션 [1] | 관리자 | 2017.02.06 | 29722 |
공지 | [전체 목록] 이 달의 기술자료 & 기술레터 | 관리자 | 2017.02.06 | 25071 |
공지 | RAD스튜디오(델파이, C++빌더) - 시작하기 [1] | 관리자 | 2015.06.30 | 46007 |
공지 | RAD스튜디오(델파이,C++빌더) - 모바일 앱 개발 사례 (2020년 11월 업데이트 됨) | 험프리 | 2014.01.16 | 181771 |
5 | 모바일 첫걸음: 델파이 iOS 개발 - 5.제스처를 사용한 탭 간 이동 | 관리자 | 2013.10.15 | 4777 |
4 | 모바일 첫걸음: 델파이 iOS 개발 - 4.사진 찍기와 공유 | 관리자 | 2013.10.08 | 4512 |
3 | 모바일 첫걸음: 델파이 iOS 개발 - 3. 웹브라우저 작성 | 손보라 | 2013.09.17 | 4414 |
2 | 모바일 첫걸음: 델파이 iOS 개발 - 2. 컴포넌트와 스타일 적용 | 관리자 | 2013.09.13 | 4110 |
1 | 모바일 첫걸음: 델파이 iOS 개발-1.첫걸음 떼기(환경 설정 등) | 관리자 | 2013.09.10 | 4506 |