2009-07-28 6 views
4

친애하는 모든 : 미리 시간을내어 고맙습니다.재귀 클래스 디자인 패턴 : 옵션 및 모범 사례

최근에 Objective-C (저는 오랫동안 C 해커였습니다)와 Kochan의 아름다운 텍스트를 읽고 Apple 설명서를 읽은 후에도 재귀 클래스 (즉, ivar의 타입이 동일한 클래스 인 인 클래스). 구체성을 위해 이진 트리 클래스를 구현한다고 가정 해 봅시다.

@interface MMNode : NSObject { 
    NSString *label; 
} 

이제 우리는 두 가지 방법으로 우리의 트리를 구현할 수 있습니다 : 먼저 우리는 I가 단순화 기본적인 노드 클래스를 가지고있다. 첫 번째 (그리고 좀 더 분명한 접근법으로 생각하는) 클래스 자체에 재귀를 배치하고 있습니다. 다음

@interface MMTree : NSObject { 
    MMNode *root; 
    MMTree *leftTree; 
    MMTree *rightTree; 
} 
@property (nonatomic, copy) MMNode *root; 
@property (nonatomic, retain) MMTree *leftTree; 
@property (nonatomic, retain) MMTree *rightTree; 

훌륭한 CHDataStructures.framework에 이용되는 제 2 방법은 데이터 구조를 구현한다

여기
typedef struct MMTreeNode { 
    MMNode *node; 
// union { 
//  struct { 
      struct MMTreeNode *leftTree; 
      struct MMTreeNode *rightTree; 
//  }; 
// }; 
} MMTreeNode; 


@interface MMTreeStruct : NSObject { 
    MMTreeNode *root; 
} 

용액은 재귀보다 "포인터 riffic"인 구조로 에 밀어 넣습니다. 주석에서 언급했듯이 익명 구조와 노동 조합은 필요하지 않지만 많은 응용 프로그램에서는 각 노드에 추가 정보가 필요하기 때문에 코드를 그대로 두겠습니다.


두 가지 솔루션을 모두 구현했으며 제대로 작동합니다. 전자는 더 직관적 인 것처럼 보입니다. 후자는 약간 더 복잡한 소스가있는 "C 중심"입니다.

후자의 기술이 선호됩니까? 그렇다면 객관적인 이유는 무엇입니까? 내가 결정할 수있는 것은 아마 구조가 고정 된 크기를 가지기 때문에 후자가 더 많은 메모리 친화적 인 것일 것이다.

다시 말씀 드리지만 StackOverflow와 CocoaHeads에 감사드립니다.

업데이트 : 추가해야, 그것은 CoreFoundation에서 객체 CFTree 비슷한 구조 구현을 사용하는 것 같다.

+0

CFTree는 'binary'일 필요는 없습니다. http://www.opensource.apple.com/source/CF/CF-635/CFTree.c에서 소스 코드를 볼 수 있습니다. 죄송합니다. 여기에 물어봐서 미안합니다. 어떤 분이 와트 목적을 말해 주시겠습니까?이 CFTree는 NSDictionary와 NSArray를 사용하여 수행 할 수 없습니다. – Tatvamasi

답변

4

CHDataStructures.framework의 저자로서, 약간의 통찰력을 추가 할 수 있기를 바랍니다. :-)

나의 엄지 손가락 규칙은 구조체를 사용할 명백한 이유가없는 한 객체를 사용하는 것입니다.

저급 데이터 구조를 구현할 때 주로 성능상의 이유로 개체 대신 구조체를 사용하기로했습니다. 객체는 인스턴스 당 약간의 메모리를 필요로 할뿐만 아니라 메서드 호출에 약간의 오버 헤드가 있습니다. 객체가 @public으로 선언 된 인스턴스 변수 만 가지고 있지만 여전히/init을 할당해야하고 Objective-C 객체 변수가 0으로 채워지는 경우 calloc()을 사용하지 않으면 구조체가 0이 아닌 객체가 완화됩니다.

Objective-C 오브젝트가 구조체보다 갖는 장점 중 하나는 가비지 콜렉션 (10.5+)과의 자동 통합이지만 원시 C 메모리는 동일한 이점을 얻기 위해 몇 개의 고리를 뛰어 넘어야한다는 것입니다. 나는 객체에 대한 메모리 관리가 Cocoa 개발자들에게 더 친숙하고 분명하다는 것에 동의한다. 그래서 클래스를 인터페이스로 사용하고 저장소를 구조체로 사용합니다.

참고 : 두 번째 코드 예제의 익명 공용 구조체 및 구조체는이 특정 상황에서는 관련이 없습니다. 더 유선형이지만 읽기 쉬운 이진 검색 트리 알고리즘을 작성할 수 있도록하기 위해서만 사용합니다. (세부 사항은 http://dysart.cs.byu.edu/CHDataStructures/struct_c_h_binary_tree_node.html입니다.) 캐주얼 한 독자를 혼란스럽게 피하기 위해 주석을 달았지만 나중에 참조 할 수 있도록 남겨 두었습니다.

+0

감사합니다. 이 코드를 보길 바랬는데 ;-) 코드를 좀 더 단순화시켜야했습니다. 원래 추가 컴퓨팅을위한 구조에 대한 정보가 더 많았습니다. 이 오버 헤드에 대한 정확한 번호가 있습니까? 100 %는 존재한다고 생각하지만, 같은 유형의 클래스를 iPhone 앱의 핵심 부분으로 사용하면 내가 살 수있는 것이면 궁금합니다. 또한 Obj-C 이론에 대한 나의 이해를 확인하기 위해 : 비 GC 응용 프로그램에 대한 적절한 @property 선언을 "보유"합니까? leftTree가 해제되고 dealloc'd 다른 권리가 싶지 않아? – SplittingField

+1

친구가 실제로 내게 게시물을 지적했다. :-) 나는 어려운 번호가 없습니다. 'isa' 포인터에 대해 객체 당 여분의 4 바이트 저장 공간 (32 비트)을 계획하십시오. 함수 호출에는 필드 액세스보다 소수 또는 두 개 이상의 명령어가 필요하며 동적 메소드 디스패치는 더 많이 추가하지만 구체적인 테스트는 실행하지 않았습니다. 어쨌든, 두 접근법은 아이폰 앱에서 사용하기에 충분해야한다. 그러나 실제로 무거운 유스 케이스의 경우 구조체를 사용하는 것이 더 이해하기 시작합니다. 특히 iPhone에서 구조체와 GC의 복잡성에 대해 염려 할 필요가 없기 때문입니다. :-) –

+1

당신이 맞습니다. 물체가 당신 아래에서 풀려날 수있는 상황이 많이 있습니다. 속성의 경우 GC 및 유지 모드에서 "유지"가 정확합니다. (많은 경우, "복사"가 바람직하지만 계층 적 데이터 구조에는 적합하지 않을 수 있습니다.) 원시 메모리를 할당하려면 크기 및 NSScannedOption과 함께 NSAllocateCollectable을 사용하여 GC가 다른 GC 관리 포인터에 대해 해당 메모리를 스캔하는지 확인합니다. GC 관리 구조체 포인터 변수에 __strong 속성을 사용하는 것이 중요하므로 루틴을 유지하고 GC가 조기에 수집하지 않도록합니다. :-) –

관련 문제