Objective-C (Cocoa)でIteratorパターンを実装してみた
Objective-C (Cocoa)でIteratorパターンを実装してみたので、貼っておきます。
NSEnumerator(外部Iterator)、高速列挙、Blocks の3種類の方法を実装してあります。
参考:
- http://www.hyuki.com/dp/ (Iteratorパターンのサンプル)
- http://journal.mycom.co.jp/column/objc/106/index.html (高速列挙)
BookShelf.h
#import <Foundation/Foundation.h> @interface Book : NSObject { @private NSString *mName; } @property (readonly) NSString *name; - (id)initWithName:(NSString *)name; + (Book *)bookWithName:(NSString *)name; @end ///// @interface BookShelf : NSObject<NSFastEnumeration> { @private NSMutableArray *mBooks; } @property (readonly) int length; - (Book *)bookAt:(int) index; - (void)appendBook:(Book *)book; - (void)foreach:(void (^)(Book *))block; - (NSEnumerator *)bookEnumerator; @end
BookShelf.m
#import "BookShelf.h" @implementation Book @synthesize name = mName; - (id)initWithName:(NSString *)name { self = [super init]; if (self) { mName = [name retain]; } return self; } + (Book *)bookWithName:(NSString *)name { return [[[Book alloc] initWithName:name] autorelease]; } - (void)dealloc { [mName release]; [super dealloc]; } @end ///// @interface BookShelfEnumerator : NSEnumerator { @private BookShelf *mShelf; int mIndex; } @end @implementation BookShelfEnumerator - (id)initWithBookShelf:(BookShelf *)shelf { self = [super init]; if (self) { mShelf = shelf; } return self; } - (id)nextObject { id obj=(mIndex>=mShelf.length)? nil : [mShelf bookAt:mIndex]; mIndex++; return obj; } @end ///// @implementation BookShelf - (id)init { self = [super init]; if (self) { mBooks = [[NSMutableArray alloc] init]; } return self; } - (void)dealloc { [mBooks release]; [super dealloc]; } - (int)length { return [mBooks count]; } - (Book *)bookAt:(int) index { return [mBooks objectAtIndex:index]; } - (void)appendBook:(Book *)book { [mBooks addObject:book]; } // NSEnumerator(外部Iterator)を使った列挙の実装 - (NSEnumerator *)bookEnumerator { return [[[BookShelfEnumerator alloc] initWithBookShelf:self] autorelease]; } // 高速列挙の実装 - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len { int count = 0; while(state->state < self.length && count < len) { stackbuf[count++] = [self bookAt:state->state++]; } state->itemsPtr = stackbuf; state->mutationsPtr = (unsigned long*)self; return count; } // Blocksを使った列挙の実装 - (void)foreach:(void (^)(Book *))block { for(Book *book in mBooks) { block(book); } } @end
利用例
#import "BookShelf.h" - (void)testBookShelf { BookShelf *shelf=[[BookShelf alloc] init]; [shelf appendBook: [Book bookWithName: @"Around the World in 80 Days"] ]; [shelf appendBook: [Book bookWithName: @"Bible"] ]; [shelf appendBook: [Book bookWithName: @"Cinderella"] ]; [shelf appendBook: [Book bookWithName: @"Daddy-Long-Legs"] ]; // NSEnumeratorの利用 { int count=0; NSEnumerator *e=[shelf bookEnumerator]; Book *book; while((book = [e nextObject])) { NSLog(@"%@", book.name); ++count; } NSLog(@"Total %d books.", count); } // 高速列挙の利用 { int count=0; for(Book *book in shelf) { NSLog(@"%@", book.name); ++count; } NSLog(@"Total %d books.", count); } // Blocksを使った列挙の利用 { __block int count=0; [shelf foreach:^(Book *book) { NSLog(@"%@", book.name); ++count; }]; NSLog(@"Total %d books.", count); } // [shelf release]; }