최초 작성일 : 2010/04/10 16:06
SimpleSectionedTableView에 추가된 내용 중 하나는 Model 클래스가 추가되었다는점이다.
Model Object는 데이터를 캡슐화 하는 핵심적인 역할을 하고 있으며 그 데이터 접근할수 있는
접근자를 제공한다. 모델 클래스들은 전통적인 행동 방식(getter를 이용하는 것?)을 내에서 값을 추가할 수 있다.
Region 클래스는 시스템으로부터 시스템이 알고있는 TimeZone 정보를 가져와
지역 이름을 추출하여 Region 인스턴스들이 담긴 regions 배열을 만들고
regions 배열에 담긴 각각의 Region 인스턴스에 있는 TimeZoneWrappers라는
인스턴스 배열 변수에 TimeZoneWrapper 클래스의 인스턴스를 설정하여
넣는다.
전체적인 구조는 Region 클래스는 지역 이름을 담당하여 지역 이름의 배열을 만들고
TimeZoneWrapper 클래스는 Time Zone 관련 데이터를 담당하여 각각의
Region 클래스의 인스턴스 안에 역시 배열로 들어간다.
regions[0]
timeZoneWrappers[0]
timeZoneWrappers[1]
timeZoneWrappers[2]
...
regions[1]
timeZoneWrappers[0]
timeZoneWrappers[1]
...
regions[2]
timeZoneWrappers[0]
timeZoneWrappers[1]
...
...
regions[0], regions[1], regions[2]는 각각 Region 클래스의 인스턴스이고
timeZoneWrappers[i]는 각각 TimeZoneWrapper 클래스의 인스턴스들이다.
@interface Region : NSObject {
NSString *name;
NSMutableArray *timeZoneWrappers;
}
//@property를 이용하여 getter와 setter 선언 자동화
//@property의 속성으로 copy가 지정된 경우. 얕은 복사가 일어난다.
//얕은 복사는 원본 데이터가 담겨있는 메모리의 주소만을 복사하여 새 변수에
//넘기고 원본의 주소는 release가 되는 형태로 복사가 이루어진다고 하여 실제로
//데이터가 2개가 되는 것은 아니다.
@property (nonatomic, copy) NSString *name;
@property (nonatomic, retain) NSMutableArray *timeZoneWrappers;
//클래스 메서드의 선언. 앞에 + 기호로 시작하는 메서드는 클래스 메서드로
//주로 클래스의 인스턴스를 생성하거나 글로벌 클래스 데이터에 접근하는 역할을 하며
//java의 static 선언과 유사하다고 생각하면 된다.
//반대로 -기호로 시작하는 메서드는 인스턴스 메서드이며 인스턴스 메서드는 클래스의
//인스턴스와 그 생명 주기를 함께 한다.
+ (NSArray *)knownRegions;
@end
Region.m
- 지역과 지역별 Time Zone 데이터를 설정하고 정렬하는 Model 클래스
//헤더파일 임포트
#import "Region.h"
#import "TimeZoneWrapper.h"
//카테고리 선언 : Private라는 이름으로 Region 클래스에 카테고리를 선언함
@interface Region (Private)
- (id)initWithName:(NSString *)regionName;
//setUpKnownRegions 메서드는 클래스 메서드로 선언도어 있으므로 인스턴스 생성 없이
//클래스로부터 바로 호출할 수 있다.
+ (void)setUpKnownRegions;
- (void)addTimeZoneWrapper:(TimeZoneWrapper *)timeZoneWrapper;
- (void)sortTimeZones;
@end
@implementation Region
//@property 키워드와 함께 name, timeZoneWrapper에 대한 getter와 setter를 자동으로 구현한다.
@synthesize name, timeZoneWrappers;
//클래스 메서드인 setUpKnownRegions을 통해 값을 설정할 수 있도록 static으로 선언된 변수
static NSMutableArray *knownRegions = nil;
//클래스 메서드인 knownRegions는 내부에서 카테고리를 통해 선언된 클래스 메서드인
//setUpKnownRegions 메서드를 호출한다. 이 때 사용된 self는 Region 클래스를 의미한다.
+ (NSArray *)knownRegions {
if (knownRegions == nil) {
[self setUpKnownRegions];
}
return knownRegions;
}
#pragma mark -
#pragma mark Memory management.
//메모리 해제...
- (void)dealloc {
//copy로 생성된 것에 대한 메모리 해제
[name release];
[timeZoneWrappers release];
[super dealloc];
}
#pragma mark -
#pragma mark Private methods for setting up the regions.
//카테고리를 통해 선언된 메서드의 구현. 인자로 받은 regionName를 통해 호출되는 copy는
//NSObject에 구현되어있으며 이 copy 메서드는 NSCopying이 적용된 subclass에서
//copyWithZone 함수를 호출하는 방식으로 동작한다. NSCopying 프로토콜은 NSString에
//적용 되어 있다.
//copy는 새로운 인스턴스 변수에 원본의 주소값을 복사한 후 retain count를 1 증가 시키므로
//release를 통해 메모리 해제를 해주어야 한다.
- (id)initWithName:(NSString *)regionName {
if (self = [super init]) {
name = [regionName copy];
timeZoneWrappers = [[NSMutableArray alloc] init];
}
return self;
}
//클래스 메서드인 setUpKnownRegions 구현
+ (void)setUpKnownRegions {
//시스템으로부터 확인된 TimeZone 이름 배열을 가져오고 그 배열의 크기와 동일하게
//변경 가능한 배열인 regions을 만든다.
NSArray *knownTimeZoneNames = [NSTimeZone knownTimeZoneNames];
NSMutableArray *regions = [[NSMutableArray alloc] initWithCapacity:[knownTimeZoneNames count]];
//knownTimeZoneNames의 크기만큼 루프를 돌면서 배열 값 하나 하나를 timeZoneName에 넣는다.
for (NSString *timeZoneName in knownTimeZoneNames) {
//knownTimeZoneNames로부터 받은 문자열을 "/"를 구분자로 나누어
//배열 nameComponents에 담는다.
NSArray *nameComponents = [timeZoneName componentsSeparatedByString:@"/"];
//배열 nameComponents의 0번째 값을 가져와 regionName에 할당한다.
NSString *regionName = [nameComponents objectAtIndex:0];
// Get the region with the region name, or create it if it doesn't exist.
Region *region = nil;
//for문을 통해 regions 배열의 값 하나 하나를 Region의 인스턴스인 aRegion에 할당한다.
for (Region *aRegion in regions) {
//regions로부터 받아온 값의 name 속성이 regionName과 같다면
//region에 aRegion을 할당하고 루프를 빠져나옴
if ([aRegion.name isEqualToString:regionName]) {
region = aRegion;
break;
}
}
//만일 name이 일치하는 경우가 없다면 regionName를 사용하여 새로운 region을 만들어
//regions에 추가한다.
if (region == nil) {
region = [[Region alloc] initWithName:regionName];
[regions addObject:region];
[region release];
}
//timeZoneName을 사용하여 NSTimeZone의 인스턴스인 timeZone을 생성하고
NSTimeZone *timeZone = [NSTimeZone timeZoneWithName:timeZoneName];
//생성된 timeZone과 timeZoneName을 배열로 만든 nameComponents를 인자로
//TimeZoneWrapper의 인스턴스를 생성한다.
TimeZoneWrapper *timeZoneWrapper = [[TimeZoneWrapper alloc] initWithTimeZone:timeZonenameComponents:nameComponents];
//생성된 timeZoneWrapper를 NSMutableArray인 timeZoneWrappers에 넣는다.
[region addTimeZoneWrapper:timeZoneWrapper];
//alloc으로 생성했으므로 메모리 해제
[timeZoneWrapper release];
}
// Now sort the time zones by name
//카테고리를 통해 추가된 함수를 호출하여 이름순으로 정렬
for (Region *aRegion in regions) {
[aRegion sortTimeZones];
}
// Sort the regions
//지역(region) 정렬
//"name" 속성을 기준으로 오름차순 정렬을 할 것임을 NSSortDescriptor클래스의 인스턴스를 통해 설정
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];
//initWithObjects 인자로 넘겨받은 C 배열로부터 count 인자로 넘겨받은 수만큼의(여기서는 1개) 객체를
//가져와 새롭게 배열로 할당한다.
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:&sortDescriptor count:1];
//sortDescriptors를 이용해 실제로 배열을 정렬한다.
[regions sortUsingDescriptors:sortDescriptors];
[sortDescriptor release];
[sortDescriptors release];
knownRegions = regions;
}
//인자로 받은 timeZoneWrapper를 NSMutableArray인 timeZoneWrappers에 넣는다.
- (void)addTimeZoneWrapper:(TimeZoneWrapper *)timeZoneWrapper {
[timeZoneWrappers addObject:timeZoneWrapper];
}
- (void)sortTimeZones {
// Sort the time zones by name
//time zones 정렬 - 상세 과정은 위의 지역 정렬 참조
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"localeName"ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:&sortDescriptor count:1];
[timeZoneWrappers sortUsingDescriptors:sortDescriptors];
[sortDescriptor release];
[sortDescriptors release];
}
@end
//TimeZoneWrapper 인터페이스
@interface TimeZoneWrapper : NSObject {
NSString *localeName;
NSTimeZone *timeZone;
}
//지역 이름과 time zone 설정을 위한 인스턴스 변수 선언 및 getter/setter 선언
@property (nonatomic, copy) NSString *localeName;
@property (nonatomic, retain) NSTimeZone *timeZone;
//초기화를 위한 인스턴스 메서드 선언
- (id)initWithTimeZone:(NSTimeZone *)aTimeZone nameComponents:(NSArray *)nameComponents;
@end
#import "TimeZoneWrapper.h"
@implementation TimeZoneWrapper
//인스턴스 변수들에 대한 getter/setter 구현
@synthesize localeName, timeZone;
- (id)initWithTimeZone:(NSTimeZone *)aTimeZone nameComponents:(NSArray*)nameComponents {
if (self = [super init]) {
//retain을 통해 인스턴스 할당. retain은 인스턴스 자신을 반환하며 참조 카운트를 1 증가 시킨다.
//인스턴스의 사용이 종료되기 전까지 메모리에서 해제하는 것을 막는다. 따라서 사용 후에 반드시
//적절한 시점에서 release를 해주어야 한다.
timeZone = [aTimeZone retain];
NSString *name = nil;
//인자로 넘어온 nameComponents 배열의 크기가 2인경우 nameComponents의
//인덱스 1에 있는 값을 retain을 통해 name으로 할당한다.
if ([nameComponents count] == 2) {
name = [[nameComponents objectAtIndex:1] retain];
}
else {
//그렇지 않은 경우 인덱스 2의 값과 인덱스 1의 값을 조합하여 name에 할당한다.
name = [[NSString alloc] initWithFormat:@"%@ (%@)", [nameComponentsobjectAtIndex:2], [nameComponents objectAtIndex:1]];
}
//name 문자열에서 "_"를 모두 " "로 바꾸어 localeName에 할당한다.
localeName = [[name stringByReplacingOccurrencesOfString:@"_"withString:@" "] retain];
[name release];
}
return self;
}
//메모리 해제
- (void)dealloc {
[localeName release];
[timeZone release];
[super dealloc];
}
@end
'Development > iPhone' 카테고리의 다른 글
[옛 글] [APIs] NSSortDescriptor (0) | 2013.07.12 |
---|---|
[옛 글] [Tip] objective-c 메서드의 종류 (0) | 2013.07.12 |
[옛 글] SimpleSectionedTableView - 소스 목록 (0) | 2013.07.12 |
[옛 글] SimpleSectionedTableView - 스크린 샷 (0) | 2013.07.12 |
[옛 글] SimpleTableView - Interface Builder (0) | 2013.07.12 |