iPhone SDK 툴킷을 사용하여 클라이언트 애플리케이션의 뷰 파트를 관리하는 제어기 클래스를 사용하는 것은 IBM WebSphere CloudBurst Appliance와 Apple iPhone 장치를 통합하는 Web 2.0 애플리케이션의 개발에서 다음 단계이다. 해당 애플리케이션은 툴킷을 사용하여 Model-View-Controller Framework를 구현한다. Part 2에서는 뷰 파트와 해당 오브젝트(예: 단추, 텍스트 상자 및 테이블 뷰)를 작성하였다. 제어기 클래스에서는 협업을 관리하는 오브젝트를 작성하였다. 이 기사에서는 애플리케이션 내에서 플로우 제어기를 관리하도록 뷰 제어기 클래스와 iPhone 애플리케이션의 해당하는 뷰 사이의 연결을 작성할 것이다.
이전 기사와 마찬가지로, 본 기사 시리즈에서는 독자들이 REST ATOM, JSON 및 Objective-C를 포함한 Web 2.0 기술을 대체로 알고 있는 것으로 가정하고 설명한다. 기사에서 설명하는 샘플 애플리케이션은 3.x 펌웨어가 설치된 iPhone 또는 iPod Touch 장치에서 실행되는 Apple iPhone SDK 3.x를 사용하여 Objective-C로 MVC(Model-View-Controller) 패턴을 사용하여 실현된다. 따라서, 이 개발은 C 프로그래밍 언어(Object-C는 C의 기능을 모두 상속함)에 대한 어느 정도의 지식을 가정한다. 이는 또한 상속, 클래스, 인터페이스 및 기타 등등과 같이 기본 오브젝트 지향 패러다임을 이해하는 것이 중요하다.
또한, 이 연습에서는 Cocoa 프레임워크를 사용하며, 이는 iPhone SDK에 대한 개발 계층을 형성하는 API 세트, 라이브러리 및 런타임 코드로 구성된다. Cocoa는 Object-C로 구현되고 MVC 패턴을 사용하여 보기, 애플리케이션 데이터, 제어기 및 클래스를 요약하여 관리 논리를 조정한다.
마지막으로 본 기사에서 설명하는 각 단계를 수행하고 예제를 실행하려면 Mac OS 호환 버전을 실행하면서 Apple SDK 3.0 이상이 설치된 컴퓨터가 필요하다. 또한, 사용자 환경에서 실행 중인 WebSphere CloudBurst Appliance에 대한 액세스 권한도 필요하다.
Cocoa 프로젝트를 작성하기 시작할 때마다 템플리트를 선택해야 한다. 이 예제의 경우 Tab Bar Application 템플리트를 선택할 것이다. 이 템플리트는 두 개의 창(그림 1 참조) 및 이들 사이에 전환할 수 있는 탭 표시줄을 생성한다.
- First View: MainWindow.xib
- Second View: SecondView.xib
그림 1. 애플리케이션 뷰
MainWindows.xib의 View Component 창을 열면 그림 2와 같은 구조가 표시될 것이다. 이는 다음으로 구성된다.
- File's Owner(Test App Delegate로 위임)
- First Responder
- Test App Delegate
- Windows (일반 창은 사용되지 않음)
- Tab Bar Controller(First View와 Second View의 두 개의 View Controllers를 관리하는 탭 표시줄 제어기)
- Tab Bar
- First View controller(First View용)
- View(FirstViewController로 관리되는 뷰)
- Tab Bar Item(First View용 Bar Controller의 항목)
- Second View controller(Second View용)
- View(FirstViewController로 관리되는 뷰)
- Tab Bar Item(Second View용 Bar Controller의 항목)
그림 2. MainWindow 구조
Navigation Controller는 애플리케이션 창의 플로우에서 보기들 사이의 탐색을 관리한다. Part 2에서 논의한 대로 세 가지 화면들 사이에 간단한 탐색을 통해 애플리케이션을 설계할 것이다. 이를 수행하려면 MainWindows에서 Navigation Controller를 정의해야 한다.
Navigation Controller는 다음 파트로 되어있다.
- Navigation Controller: 이는 탐색 이벤트를 처리하고 이를 모두 함께 연결하는 컨트롤러 오브젝트이다.
- Navigation Bar: 이는 사용자가 탐색 계층을 통해 진행할 곳을 확인할 수 있고 뒤로 탐색할 수 있는 맨 위에 있는 표시줄이다.
- View Controller: 이는 보유(hold) 뷰와 관련된 View Controller이다.
- Navigation Item: 탐색 항목은 Navigation Bar 바둑판식 배열에 있고 탐색하기 위한 단추가 있다.
MainWindow.xib 컴포넌트 창에서 Tab Bar Controller 컴포넌트에 정의된 첫 번째 뷰 제어기를 변경한다.
- MainWindow 컴포넌트 창에서 Tab bar controller를 선택한다.
- Attribute View를 선택하고 그림 3과 같이 "First"라는 이름의 View Controller 클래스를
View Controller에서Navigation Controller로 변경한다.
그림 3. Navigation Controller 클래스 정의
Navigation Controller 클래스를 통해 애플리케이션 뷰 사이에 탐색을 관리할 수 있다. 이 프로젝트에서는 OneView.xib 파일에서 첫 번째 뷰를 작성할 것이다(OneViewController 클래스 사용). MainWindow를 OneView로 대체해야 한다.
- 맨 위 창을 클릭하여 First 뷰가 들어있는 창을 선택한다.
- 뷰 내의 First View 패널을 선택하고 이를 삭제한다.
참고: 레이블을 선택하면 안 된다. 그림 4에서 삭제 후의 뷰를
확인할 수 있다.
그림 4. Main View
- 해당 뷰 창에서 View의 회색 부분 안쪽을 클릭하여 빈 뷰를 선택하도록 한다.
- View Controller 속성에서 드롭 다운 목록을 사용하여 OneView라는 NIB 파일을 삽입한다.
그림 5. OneView
- 왼쪽 패널의 중간 부분에 있는 One View 파란색 링크를 클릭하여 One View 뷰를 연다.
- View Component 뷰에서 File's Owner를 선택한다.
- Class 드롭 다운 목록을 사용하여 선택한 One View 뷰에
OneViewController 뷰 제어기 클래스를 지정한다. 이는
OneViewController 클래스가 OneView 뷰의 제어기임을 의미한다(그림 6).
그림 6. OneView 제어기 클래스
- 모든 변경 사항을 저장한다.
- Build > Build and Run을 선택하여 애플리케이션을 테스트할 수 있다.
이제 애플리케이션에서 첫 번째 열린 창으로 OneView를 확인할 수 있다.
OneViewController 클래스를 작성했을 때, 뷰 컴포넌트를 관리하기 위해 인스턴스 변수를 정의했다. 이러한 변수는 다음과 같다.
- field1: 첫 번째 입력 필드용
- field2: 두 번째 입력 필드용
- description: 테스트 텍스트 필드용
이러한 변수를 각 뷰 컴포넌트로 지정해야 한다. field1을 연결하는 방법을 살펴보자. (해당하는 인스턴스 변수로 모든 뷰 컴포넌트에 대해 이 조치를 반복할 것이다.)
- Interface Builder에서 OneView를 연다.
- File's Owner를 선택한다. 이는 OneViewController 클래스가 되어야 한다.
- 마우스 오른쪽 단추를 사용하여 그림 7과 같이 첫 번째 텍스트 필드에 대해
File's Owner 행을 끌어 놓는다.
그림 7. 인스턴스 변수 지정
- 끌어 놓기 조치의 종료 시 나타나는 메뉴에서 이 컴포넌트로 지정된 변수를 선택한다.
그림 8. 변수 테이블
- 모든 뷰 컴포넌트에 대해 동일한 조치를 반복한다. 각 뷰 컴포넌트에 대해 해당하는 인스턴스 변수를 선택한다.
종료 시에 모든 인스턴스 변수가 이제 뷰 컴포넌트로 지정된다.
OneView에 다음 세 개의 단추가 있다.
- test :
(IBAction) buttonPressedTest로 지정되는 용도 - load :
(IBAction) buttonDownload로 지정되는 용도 - next :
(IBAction) buttonNext로 지정되는 용도
각 조치를 관련된 단추 뷰 컴포넌트로 지정해야 한다. 이제 테스트 단추를 연결할 것이다. (해당하는 메소드로 모든 단추에 대해 동일한 조치를 반복할 것이다.)
- OneView 컴포넌트 창에서 Test 단추를 선택한다.
- Button Connection에서 모든 단추 이벤트를 확인할 수 있다.
- 마우스 왼쪽 단추를 사용하여 Touch Down과 같이 관리하려는 조치를 File's Owner 행에 끌어 놓는다.
- 끌어 놓기 조치의 종료 시 나타나는 목록에서 메소드를 선택한다(예를 들어, buttonPressedtest).
- 모든 단추에 동일한 조치를 반복한다. 각 단추 컴포넌트에 해당하는 메소드를
선택한다.
그림 9. OneViewController 연결
이제 buttonPressedTest 및 buttonNext를 관리하는 데 필요한 모든 코드를 클래스에 삽입할 수 있다. buttonPressedTest 메소드는 responseString 변수에서 테스트 파일인 example.sql을 로드한다(목록 1 참조).
목록 1. (IBAction) buttonPressedTest
<![CDATA[
(IBAction) buttonPressedTest
{
[field1 resignFirstResponder];
[field2 resignFirstResponder];
NSString *filePath = [[NSBundle mainBundle]
pathForResource:@"example"
ofType:@"sql"];
NSString *responseString = [NSString stringWithContentsOfFile:filePath];
NSLog(@"responseString:%@",responseString);
description.text = responseString;
}]]> |
example.sql 파일은 목록 2와 같은 항목이 들어있다.
목록 2. example.sql
[
{
"desiredstatus_text": null,
"currentstatus_text": "Stopped",
"created": 1260941860895,
"name": "Single Server",
"currentstatus": "RM01011",
"desiredstatus": null,
"currentmessage": "RM07153",
"pattern": "/resources/patterns/1",
"owner": "/resources/users/6",
"updated": 1260943821497,
"id": 51,
"currentmessage_text": "Stopped"
},
{
"desiredstatus_text": null,
"currentstatus_text": "Running",
"created": 1263868560454,
"name": "05WASadmin Cloned Lab Virtual System",
"currentstatus": "RM01005",
"desiredstatus": "",
"currentmessage": "RM07054(\"05WASAdmin+Lab+Application\",\"05WASadmin+Cloned+Lab+
Virtual+System+vm-001-016+dmgr\")",
"pattern": "/resources/patterns/43",
"owner": "/resources/users/15",
"updated": 1263869039755,
"id": 59,
"currentmessage_text": "script package of 05WASAdmin Lab Application
on VM 05WASadmin Cloned Lab Virtual System vm-001-016 dmgr"
},
{
"desiredstatus_text": null,
"currentstatus_text": "Stopped",
"created": 1263857152896,
"name": "Financial Application Test Group Sys 05",
"currentstatus": "RM01011",
"desiredstatus": null,
"currentmessage": "RM07153",
"pattern": "/resources/patterns/1",
"owner": "/resources/users/15",
"updated": 1263863898994,
"id": 54,
"currentmessage_text": "Stopped"
},
{
"desiredstatus_text": null,
"currentstatus_text": "Run",
"created": 1263857159858,
"name": "John",
"currentstatus": "RM01006",
"desiredstatus": "",
"currentmessage": "RM07045",
"pattern": "/resources/patterns/1",
"owner": "/resources/users/14",
"updated": 1263857536925,
"id": 55,
"currentmessage_text": "The VM is available"
},
{
"desiredstatus_text": null,
"currentstatus_text": "Run",
"created": 1263862881511,
"name": "LucaV",
"currentstatus": "RM01006",
"desiredstatus": "",
"currentmessage": "RM07045",
"pattern": "/resources/patterns/1",
"owner": "/resources/users/4",
"updated": 1263863256864,
"id": 56,
"currentmessage_text": "The VM is available"
}
] |
buttonNext 메소드는 목록 3과 같이 ListElement 뷰를 호출하고 ListElementViewController를 인스턴스화할 것이다.
목록 3. (IBAction) buttonNext
<![CDATA[
-(IBAction) buttonNext
{
[field1 resignFirstResponder];
NSString *server = field1.text;
ListElementViewController *listElementController =
[[ListElementViewController alloc]
initWithNibName:@"ListElementView"
bundle:nil];
NSLog(@"func UnoViewController.buttonNext ");
[listElementController setDescpText:server];
[self.navigationController pushViewController:listElementController
animated:YES];
]]>
[listElementController loadJsonText:description.text];
<![CDATA[
}
]]> |
loadJsonText 메소드는 WCA로부터 ListElementViewController로 수신된 데이터를 삽입한다. 수신된 데이터는 해당 뷰에서 목록을 표시하는 데 사용된다.
ListElement 뷰는 Table View 컴포넌트라는 하나의 뷰 컴포넌트만으로 구성된다. 이 컴포넌트는 뷰 제어기 클래스 내부에 지정된 인스턴스 변수가 없지만, 클래스 위임을 정의해야 한다. 필요한 모든 테이블 뷰 조치를 관리하기 위해 메소드를 많이 정의해야 하기 때문에 이 작업은 필수적이다. 해당 프레임워크는 필요할 때마다 클래스 위임을 호출할 것이며, 클래스는 모든 필수 메소드를 구현해야 한다. 이러한 메소드는 다음과 같다.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
클래스 위임 내부에서 이러한 메소드를 작성한다. ListElement 뷰의 클래스 위임을 정의한다. 간소화하기 위해 두 가지 메소드인 뷰 제어기 및 테이블 뷰 위임에 대해 동일한 클래스(예: ListElementViewController)를 사용할 것이다.
- ListElementView.xib 파일을 열고 Identity 뷰에서 ListElementViewController 클래스를 삽입한다.
- 뷰 컴포넌트 창에서 Table View 컴포넌트를 선택한다.
- Table View connection을 선택한다.
- 마우스 왼쪽 단추를 사용하여 dataSource 태그에서부터 뷰 컴포넌트 창의 File's Owner로 끌어 놓는다.
- delegate 태그에 동일한 작업을 수행한다.
그림 10은 결국에Table View 연결을 보여준다.
그림 10. Table view dataSource 및 delegate
이 뷰는 호출자 뷰 제어기로부터 JSON 데이터 파일을 수신한다. 이 솔루션에서 이전 뷰는 네트워크 연결 프로토콜을 관리한다. 이 뷰는 대신에 데이터를 관리하겠지만(이는 데이터가 도착한 지점을 알지 못함) 텍스트 문자열(JSON과 유사하게 형식화됨)을 Objective-C 데이터 오브젝트로 변환해야 한다. 사전을 취하기 위해 VirtualSystems 클래스를 사용할 것이다. Part 2에서 논의한 대로, 이 클래스에서 JSON 구문 분석기를 포함할 것이다. 클래스 선언의 맨 위에 이를 수행하려면 다음을 포함해야 한다.
- #import "JSON/JSON.h": 이는 선택한 JSON 구문 분석기에 따라 달라야 한다.
- #import "VirtualSystems.h": 이는 해당 클래스를 포함하여 JSON 데이터 오브젝트를 취한다. JSON 텍스트 파일에 있는 각 요소는 VirtualSystems 오브젝트로 변환된다.
호출자 클래스(OneViewController)와 ListElementViewController 사이에 연결은 목록 4와 같이 다음 코드 메소드로 수행된다.
목록 4. IBAction) loadJsonText:(NSString *)jsonString.h
<![CDATA[
- (IBAction) loadJsonText:(NSString *)jsonString{
NSLog(@"func UnoViewController.loadJsonText :%@ ",jsonString);
NSError *error;]]><![CDATA[
SBJSON *json = [[SBJSON new] autorelease];
NSArray *luckyNumbers = [json objectWithString:jsonString
error:&error];
]]>
<![CDATA[for (int i = 0; i < [luckyNumbers count]; i++)
{
NSLog(@"number:%@",[luckyNumbers objectAtIndex:i]);
NSDictionary *tmpDict= [luckyNumbers objectAtIndex:i];
VirtualSystems *elem = [[VirtualSystems alloc]
initWithJSON:tmpDict name:@"test"];
[listElement addObject:elem];
[elem release];
}
}
]]> |
선택한 JSON 구문 분석기에 따라 굵은체의 코드를 확인할 수 있다. 구문 분석기 지시사항에 따라 이러한 코드 행을 변경한다. 이 예제에서 이 메소드는 SBJSON 오브젝트를 사용하여 데이터 오브젝트 배열을 구문 분석하고 확보한다. 이 배열에 있는 각 요소에 대해 VirtualSystems 오브젝트를 작성하고 인스턴스 변수인 listElement에서 이를 로드할 것이다.
확인 가능한 대로 여기에서는 NSDictionary 오브젝트를 사용했다. Objective-C에서 사전은 두 가지 정보 세트인 고유 키와 연관된 값을 보유하는 오브젝트이며, 해당 키를 사용하여 항목을 검색할 수 있다. 중재 키와 연관된 데이터를 검색하는 편리하고 효율적인 방법이 필요할 때 이러한 오브젝트 종류를 사용해야 한다. 해당 키는 대개 정수 또는 문자열이며, 항목은 유형에 관계없이 가능하다. NSDictionary를 사용했기 때문에, 정적 사전을 작성했다. 키와 관련된 값을 구성하는 각 행은 입력이라고 한다. 사전 내에서 키는 고유하다. 키나 값 중 어느 하나도 널이 될 수 없다(사전에서 널값이 필요하면 대신 "NSNull"을 사용한다). 독자는 JSON 파일로부터 데이터를 추출했고 tmpDict라는 Dictonary 오브젝트 파일에 정보를 맵핑했다. 사용한 JSON 구조에 따라 Dictionary 오브젝트는 다음 필드를 가진다.
- desiredstatus_text
- currentstatus_text
- created
- name
- currentstatus
- desiredstatus
- currentmessage
- pattern
- owner
- updated
- id
- currentmessage_text
이러한 필드는 각 항목에 대해 JSON 파일로부터 추출된 값이 포함될 것이다. JSON 구조의 각 노드에 대해 하나의 입력이 있을 것이다. 이 경우에는 다섯 개의 입력을 가질 것이다.
독자는 ListElement 뷰에서 간단한 Table 뷰를 삽입할 것이다. 하나의 더 많은 레이블이 있는 복잡한 목록 하나와 행 테이블 내부에서 아이콘 하나를 작성할 것이다. 이를 수행하는 방법이 많다. 여기에서 사용한 방법은 어느 그래픽 인터페이스도 사용하지 않으므로, 코드를 사용하여 테이블 뷰 내부로 각 뷰 컴포넌트를 삽입할 것이다.
이 기능은 cellForRowAtIndexPath 메소드에서 구현된다. 이 메소드는 시스템이 테이블 뷰의 어느 한 행을 빌드하는 방법을 이해해야 할 때마다 호출된다. 이러한 방식으로 서로 다른 행을 작성할 수 있다. 메소드 면의 수고를 덜기 위해 두 개의 다른 블록에서 메소드를 빌드할 것이다.
- cell==nil: 이 테스트는 처음에만 적용된다. 해당 행에 대한 셀을 작성할 것이다.
- cell!=nil: 이는 셀 행이 이미 작성되었음을 의미한다. 값만 셀 태그로 지정해야 한다. 이 경우에는 뷰 셀 테이블 작성을 건너뛴다.
이 메소드를 사용하여 화면 레이아웃에서 정확한 컴포넌트 위치를 사용하여 코딩(셀 작성 도중에)을 설정해야 한다. 이를 수행하려면 한 지점씩 정확한 Frame 직사각형을 정의해야 한다(목록 5).
목록 5. cellForRowAtIndexPath 메소드
<![CDATA[
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"ImageOnRightCell";
UILabel *mainLabel, *secondLabel;
UIImageView *photo;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:
CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier] autorelease];
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
mainLabel = [[[UILabel alloc]
initWithFrame:CGRectMake(0.0, 0.0, 290.0, 18.0)] autorelease];
mainLabel.tag = MAINLABEL_TAG;
mainLabel.font = [UIFont systemFontOfSize:14.0];
mainLabel.textAlignment = UITextAlignmentRight;
mainLabel.textColor = [UIColor blackColor];
mainLabel.autoresizingMask =
UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleHeight;
[cell.contentView addSubview:mainLabel];
secondLabel = [[[UILabel alloc]
initWithFrame:CGRectMake(0.0, 20.0, 265.0, 25.0)] autorelease];
secondLabel.tag = SECONDLABEL_TAG;
secondLabel.font = [UIFont systemFontOfSize:12.0];
secondLabel.textAlignment = UITextAlignmentRight;
secondLabel.textColor = [UIColor darkGrayColor];
secondLabel.autoresizingMask =
UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleHeight;
[cell.contentView addSubview:secondLabel];
photo = [[[UIImageView alloc]
initWithFrame:CGRectMake(270.0, 18.0, 25.0, 25.0)] autorelease];
photo.tag = PHOTO_TAG;
photo.autoresizingMask =
UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleHeight;
[cell.contentView addSubview:photo];
} else {
mainLabel = (UILabel *)[cell.contentView viewWithTag:MAINLABEL_TAG];
secondLabel = (UILabel *)[cell.contentView viewWithTag:SECONDLABEL_TAG];
photo = (UIImageView *)[cell.contentView viewWithTag:PHOTO_TAG];
}
VirtualSystems *vs = (VirtualSystems *) [listElement
objectAtIndex:indexPath.row];
mainLabel.text = [vs getName];
secondLabel.text = [NSString stringWithFormat:@"%i",[vs getId]];
NSString *status=[vs getCurrentstatus];
NSString *imagePath = [[NSBundle mainBundle] pathForResource:status
ofType:@"png"];
UIImage *theImage = [UIImage imageWithContentsOfFile:imagePath];
photo.image = theImage;
return cell;
}
]]> |
사용자가 테이블에서 특정 행을 선택할 때, 선택한 행에서 표시된 가상 시스템을 식별하고 listElement 배열로부터 데이터를 검색하며 ListElementView 및 해당 뷰 제어기를 호출해야 한다.
메소드 didSelectRowAtIndexPath는 선택 조치가 수행될 때 해당 뷰가 호출할 것이다. 메소드가
목록에서 선택한 요소의 인덱스를 수신하면,
listElement 요소를 식별하고 추출하며 setVirtualSystem 작동을 사용하여
DetailSystemViewController에 밀어넣기 위해 이 인덱스를 사용할 것이며, 이는 목록 6에 표시되어 있다.
이 뷰를 마무리하기 전에 선택한 행을 선택 취소한다.
목록 6. didSelectRowAtIndexPath 메소드
<![CDATA[
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
VirtualSystems *elem = (VirtualSystems *)[listElement
objectAtIndex:indexPath.row];
DetailSystemViewController *dettaglioController =
[[DetailSystemViewController alloc]
initWithNibName:@"DetailSystemView" bundle:nil];
NSLog(@"func didSelectRowAtIndexPath elem.keyID:%i",indexPath.row);
[dettaglioController setVirtulaSystem: elem];
[self.navigationController pushViewController:dettaglioController
animated:YES];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
]]> |
이 뷰는 VirtualSystems 오브젝트의 인스턴스로 단일 시스템의 정보를 수신했다. 이 오브젝트는
ListElement 뷰에서 사용자가 선택한 요소이다. 오브젝트는
-(void)setVirtualSystems:의 작동을 사용하여 aSystem 인스턴스
변수에 저장된다. 오브젝트 내의 값은 정보를 뷰 요소로 지정하는 데 사용되고
이를 사용자에게 표시하는 데 사용된다. 다음과 같이 시스템 상태를 설명하도록 아이콘을 사용할
것이다(다운로드 섹션에서 아이콘 예제를 찾을 수 있지만,
다른 아이콘들도 사용할 수 있다).
- RM01011: 시스템 중지됨
- RM01006: 시스템 실행 중
- RM01005: 시스템 상태를 알지 못함
다음과 같이 선택한 아이콘을 프로젝트로 로드한다.
- 아이콘을 Mac 파일 시스템 내로 로드한다.
- 이를 각각
RM01005.png,RM01006.png및RM01011.png로 이름을 바꾼다. - 이 시리즈의 첫 기사에서 설명한 대로 Add > Existing Files를 선택한다.
코드를 간소화하려면 아이콘을 REST 신디케이션으로 검색된 동일한 상태 코드로 지정한다.
aSystem 인스턴스 변수로부터
-(void)viewDidLoad 메소드에서 뷰 컴포넌트로 지정 값을
설정할 것이다. 목록 7 및 8에서 DetailSystemsViewController 코드를 확인할 수 있다.
목록 7. DetailSystemsViewController.h
<![CDATA[
//
// DetailSystemViewController.h
// WCA000
//
// Created by luca amato on 9/27/10.
//
#import <UIKit/UIKit.h>
#import "VirtualSystems.h"
@interface DetailSystemViewController : UIViewController {
IBOutlet UILabel *name;
IBOutlet UILabel *currentStatusText;
IBOutlet UILabel *created;
IBOutlet UILabel *owner;
IBOutlet UIImageView *statusImg;
IBOutlet UITextView *currentMessageText;
VirtualSystems *aSystem;
}
@property (nonatomic, retain) VirtualSystems *aSystem;
- (void)setVirtulaSystem:(VirtualSystems *)system;
@end]]> |
목록 8. DetailSystemsViewController.m
<![CDATA[
//
// DetailSystemViewController.m
// WCA000
//
// Created by luca amato on 9/27/10.
//
#import "DetailSystemViewController.h"
@implementation DetailSystemViewController
// Implement viewDidLoad to do additional setup
// after loading the view, typically from a nib.
- (void)viewDidLoad {
NSString *status=[aSystem getCurrentstatus];
NSString *imagePath = [[NSBundle mainBundle]
pathForResource:status ofType:@"png"];
statusImg.image = [UIImage imageWithContentsOfFile:imagePath];
self.title=[NSString stringWithFormat:@"%i",[aSystem getId]];
name.text=[aSystem getName];
created.text=[aSystem getCreated];
currentStatusText.text = [aSystem getCurrentstatusText];
currentMessageText.text = [aSystem getCurrentmessage];
NSObject *tmp=[aSystem getCreated];
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
}
- (void)dealloc {
[super dealloc];
}
- (void)setVirtulaSystem:(VirtualSystems *)system {
aSystem = system;
}
@end]]> |
이제 파일을 저장할 수 있다. 옵션 메뉴로부터 File > Save를 선택한다.
많은 사용자 애플리케이션에서 애플리케이션 상태를 저장하는 것은 유용하다. 저장된 정보는 다음에 애플리케이션을 시작할 때 정확한 필드에서 애플리케이션에 사용된 최종 값이 검색될 것이다.
이를 수행하는 방법이 많다. 여기에서는 간단한 파일을 사용하여 이 기능을 구현할 것이다. SDK 프레임워크는 오브젝트(스칼라 값 포함)를 아키텍처 독립적인 형식으로 인코드하는 방법을 제공한다. 파일에서 오브젝트를 저장하기 위해 이 클래스를 사용할 수 있다. 이 키입력(keyed) 아카이브는 NSKeyedArchiver로 실현된다. 자세한 정보는 Cocoa 라이브러리 참조 문서를 참조하자. 첫 번째 애플리케이션 클래스(OneViewController)가 인스턴스화될 때 데이터를 검색할 것이다. 처음에 아카이브된 파일이 있는지 확인해야 한다. 존재하지 않는 경우 빈 파일을 작성해야 한다. 최종 클래스를 배치할 때마다 상태 정보를 파일로 쓸 것이다.
우수한 오브젝트 지향적 접근방식의 경우, 필요한 상태 키 값을 모두 관리하기 위해
특정 클래스를 작성할 것이다. 상태 파일에 저장하기 위해 네 개의 값을 가지기로
되어있다. 따라서, FourLines 클래스를 작성한다.
이 클래스는 네 개의 값을 관리하며, 각 값은 특정 필드 키가 있다. 독자는 h 파일에서 상수로
필드 키 값을 정의할 것이다. 이는
Field1,Field2,Field3,Field4이다.
Field1 FourLine 키에서 서버 이름(field1에서 나옴), Field2 FourLines 키에서 사용자 ID(field2에서 나옴)를 저장한다(목록 9 및 10). 보안 상의 이유로 비밀번호는 애플리케이션 상태에서 저장되지 않는다.
목록 9. FourLines.h
<![CDATA[
//
// FourLines.h
// WCA000
//
// Created by luca amato on 9/27/10.
//
#import <Foundation/Foundation.h>
#define FIELD1KEY @"Field1"
#define FIELD2KEY @"Field2"
#define FIELD3KEY @"Field3"
#define FIELD4KEY @"Field4"
@interface FourLines : NSObject <NSCoding, NSCopying> {
NSString *field1 ;
NSString *field2 ;
NSString *field3 ;
NSString *field4 ;
}
@property (nonatomic, retain) NSString *field1;
@property (nonatomic, retain) NSString *field2;
@property (nonatomic, retain) NSString *field3;
@property (nonatomic, retain) NSString *field4;
@end
]]>
|
목록 10. FourLines.m
<![CDATA[
//
// FourLines.m
// Persistence
//
// Created by luca amato on 9/11/10.
//
#import "FourLines.h"
@implementation FourLines
@synthesize field1;
@synthesize field2;
@synthesize field3;
@synthesize field4;
#pragma mark NSCoding
-(void)encodeWithCoder:(NSCoder *)encoder
{
[encoder encodeObject:field1 forKey:FIELD1KEY];
[encoder encodeObject:field2 forKey:FIELD2KEY];
[encoder encodeObject:field3 forKey:FIELD3KEY];
[encoder encodeObject:field4 forKey:FIELD4KEY];
}
-(id)initWithCoder:(NSCoder *)decoder
{
if (self = [super init])
{
self.field1 = [decoder decodeObjectForKey:FIELD1KEY];
self.field2 = [decoder decodeObjectForKey:FIELD2KEY];
self.field3 = [decoder decodeObjectForKey:FIELD3KEY];
self.field4 = [decoder decodeObjectForKey:FIELD4KEY];
}
return self;
}
#pragma mark -
#pragma mark NSCopying
-(id)copyWithZone:(NSZone *)zone
{
FourLines *copy = [[[self class] allocWithZone:zone] init];
field1 = [self.field1 copy];
field2 = [self.field2 copy];
field3 = [self.field3 copy];
field4 = [self.field4 copy];
return copy;
}
@end
]]>
|
목록 11과 같이 코드의 일부분은 저장된 파일을 검색하고 FourLines 클래스로부터 특정 필드 값을 추출한다.
목록 11. FourLines 검색
<![CDATA[ . . NSData *data = [[NSMutableData alloc] initWithContentsOfFile:[self dataFilePathPersistence]]; NSKeyedUnarchiver *unarch = [[NSKeyedUnarchiver alloc] initForReadingWithData:data]; FourLines *fourLines = [unarch decodeObjectForKey:DATAKEY]; [unarch finishDecoding]; field1.text = fourLines.field1; field2.text = fourLines.field2; [unarch release]; [data release]; . .]]> |
목록 12의 일부 코드가 FourLines 클래스를 저장한다.
목록 12. FourLines 저장
<![CDATA[ . . FourLines *fourLines = [[FourLines alloc] init]; fourLines.field1 = field1.text; fourLines.field2 = field2.text; fourLines.field3 = @"uno"; fourLines.field4 = @"due"; NSMutableData *data = [[NSMutableData alloc] init]; NSKeyedArchiver *arch = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data]; [arch encodeObject:fourLines forKey:DATAKEY]; [arch finishEncoding]; [data writeToFile:[self dataFilePathPersistence] atomically:YES]; . .]]> |
OneViewController 클래스에서 이러한 코드 부분 및 -(void)DidLoad 메소드에서 검색 메소드 코드를 삽입할 것이다. 이는 OneView가 로드된 후 호출될 것이다.
-(void)applicationWillTerminate 메소드에서 저장된 코드는 OneView가 파괴될 때 호출된다. 목록 13에서 언플러그드 모드로 작업하는 OneViewController 클래스의 완료된 코드를 확인할 수 있다. 독자가 확인 가능한 대로 JSON 데이터가 example.sql이라는 정적 파일로부터 검색된다.
목록 13. OneViewController.m
<![CDATA[
//
// UnoViewController.m
// WCA000
//
// Created by luca amato on 9/25/10.
//
#import "UnoViewController.h"
#import "ListElementViewController.h"
#import "FourLines.h"
#import "AlertPrompt.h"
@implementation UnoViewController
@synthesize inputString;
@synthesize field1 ;
@synthesize field2 ;
@synthesize description;
// Implement viewDidLoad to do additional setup
// after loading the view, typically from a nib.
- (void)viewDidLoad {
self.title = @"WCA Server";
NSString *filePath = [self dataFilePathPersistence];
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath])
{
NSData *data = [[NSMutableData alloc]
initWithContentsOfFile:[self dataFilePathPersistence]];
NSKeyedUnarchiver *unarch = [[NSKeyedUnarchiver alloc]
initForReadingWithData:data];
FourLines *fourLines = [unarch decodeObjectForKey:DATAKEY];
[unarch finishDecoding];
field1.text = fourLines.field1;
field2.text = fourLines.field2;
[unarch release];
[data release];
}
UIApplication *app = [UIApplication sharedApplication];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(applicationWillTerminate:)
name:UIApplicationWillTerminateNotification object:app
];
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
}
- (void)viewDidUnload {
}
- (void)dealloc {
[super dealloc];
}
-(NSString *)dataFilePath
{
NSArray *path = NSSearchPathForDirectoriesInDomains
(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDirectory = [path objectAtIndex:0];
return [documentDirectory stringByAppendingPathComponent: FILENAMEARCH];
}
-(IBAction) buttonDownloadImage
{
}
-(IBAction) buttonPressedTest
{
[field1 resignFirstResponder];
[field2 resignFirstResponder];
NSString *filePath = [[NSBundle mainBundle]
pathForResource:@"example" ofType:@"sql"];
NSString *responseString = [NSString stringWithContentsOfFile:filePath];
NSLog(@"responseString:%@",responseString);
description.text = responseString;
}
-(IBAction) buttonNext
{
[field1 resignFirstResponder];
NSString *server = field1.text;
ListElementViewController *listElementController =
[[ListElementViewController alloc]
initWithNibName:@"ListElementView" bundle:nil];
NSLog(@"func UnoViewController.buttonNext ");
[listElementController setDescpText:server];
[self.navigationController pushViewController:listElementController
animated:YES];
[listElementController loadJsonText:description.text];
}
-(NSString *)dataFilePathPersistence
{
NSArray *path = NSSearchPathForDirectoriesInDomains
(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDirectory = [path objectAtIndex:0];
return [documentDirectory stringByAppendingPathComponent: FILENAMEARCH];
}
-(void)applicationWillTerminate:(NSNotification *)notification
{
FourLines *fourLines = [[FourLines alloc] init];
fourLines.field1 = field1.text;
fourLines.field2 = field2.text;
fourLines.field3 = @"uno";
fourLines.field4 = @"due";
NSMutableData *data = [[NSMutableData alloc] init];
NSKeyedArchiver *arch = [[NSKeyedArchiver alloc]
initForWritingWithMutableData:data];
[arch encodeObject:fourLines forKey:DATAKEY];
[arch finishEncoding];
[data writeToFile:[self dataFilePathPersistence] atomically:YES];
[fourLines release];
[arch release];
[data release];
}
@end
]]>
|
모든 파일을 저장하도록 한다. 이제 Go 메뉴로부터 Build > Build를 선택하여 애플리케이션을 테스트할 수 있다. 어떤 오류를 발견하면, 이를 제거하고 프로젝트를 재컴파일한다.
기본 화면에서 애플리케이션을 테스트하려면 Test 단추를 클릭한다. 맨 아래 테스트 파일을 확인할 수 있다. Next 단추를 클릭한다.창은 예제 JSON 파일에서 정의한 서버 목록을 표시한다. 행에 있는 시스템을 선택할 수 있다. 그러면 애플리케이션은 다음 뷰(DetailSystemView)에서 선택한 시스템 세부사항을 표시할 것이다. 각 뷰에서 뷰의 맨 위에 있는 탐색 도구 표시줄에서 단추를 사용하여 돌아갈 수 있다. 뒤로 단추를 사용하여 이전 뷰의 제목을 확인한다.
이 기사에서 Cocoa 프레임워크를 사용하여 MVC 프레임워크의 제어기 파트를 작성하였다. 제어기 클래스는 GUI를 관리하고 Navigation Controller를 구현하며 뷰 컴포넌트를 연결하며 GUI의 각 단추로 조치를 지정한다. 하지만, 애플리케이션은 HTTPS 프로토콜을 관리하지 않는다. WebSphere Cloudburst Appliance와 통신하려면 보안 관리를 비롯하여 네트워크 요소를 구현해야 할 것이며, 이는 이 시리즈의 결론에서 설명한다.
| 설명 | 이름 | 크기 | 다운로드 방식 |
|---|---|---|---|
| Sample code | 1105_amato1_WCAsample.zip | 1.5MB | HTTP |
-
IBM WebSphere Cloudburst Appliance 제품 정보
-
developerWorks 클라우드
컴퓨팅 영역
- 시리즈: Managing your private cloud
- 시리즈: Cloud
computing for the enterprise
-
Enable C++ applications for Web service using XML-RPC
-
Apple Developer resources
-
Mac OS X Cocoa Frameworks
-
iOS Dev Center
-
JSON
-
Objective-C tutorial
-
developerWorks WebSphere Application Server 영역
-
IBM developerWorks WebSphere 페이지

Luca Amato는 소프트웨어 개발 분야에서 15년 이상의 경험을 보유한 IBM 공인 아키텍트이다. 그는 웹 기술을 기반으로 하는 수많은 프로젝트에 컨설턴트 겸 프로젝트 리더로 참여했다. Luca는 이탈리아의 피사대학교에서 정보 기술 학위를 취득하고 파비아대학교 정보학과에서 언어 이론 과정을 강의하고 있다. Luca는 이탈리아 밀라노에 있는 IBM Italy의 WebSphere 통합 솔루션 아키텍트이다. 그는 SOA 기반 솔루션에서 다년간의 경험을 쌓으며 WebSphere 그룹에서 일하고 있다. 그는 IBM 오픈 소스 커뮤니티 구성원이기도 하다.

Alessandro Bartoli는 소프트웨어 개발 분야에서 다년간의 경험을 쌓은 IBM 컨설턴트이다. 그는 몇몇 IT 거버넌스 관리 프로젝트에서 컨설턴트로 일했고 ITIL(Information Tecnology Infrastructure Library) v3에서 4개의 인증 자격을 보유하고 있다. 과거에 그는 WebSphere Application Server, WebSphere Portal 및 WebSphere Process Server 환경을 위한 IT 아키텍트로 일하기도 했다. Alessandro는 밀라노의 Politecnico에서 정보기술공학 석사 학위를 취득했다.