2010-08-12 3 views
0

Я определенно новичок, когда дело доходит до Objective-C! Любая помощь была бы чрезвычайно оценена.Правильная конструкция класса NSFastEnumeration

Этот код работает для меня, но я действительно чувствую, что он обязательно взорвется на меня в будущем. Например, что, если кто-то называет автозапуск сливом в середине цикла for. Кроме того, что это за разница между itemPtr и stackbuf? Документация NSFastEnumeration на сайте Apple, на самом деле слабый и мой код не ведет себя так, как описано:

stackbuf 
    A C array of objects over which the sender is to iterate. 
itemsPtr 
    A C array of objects

Это не очень полезно. Я использую только itemsPtr, и он работает. Что именно я должен делать с stackbuf и как я должен обрабатывать выделение/освобождение памяти stackbuf и itemsPtr ??? Я прочитал эту дискуссию о macosx-dev (2009-октябрь) Внедрение NSFastEnumeration и чувствую себя еще менее уверенным в том, что я имею представление о том, что происходит.

Итак ... помогите! Это правильно? Как я могу сделать это лучше? Что мне делать с stackBuf? Как мне не попасть в беду с перерывом?

код в качестве исходного файла: http://vislab-ccom.unh.edu/~schwehr/Classes/2010/mbnutsandbolts/simple-fast-enum2.m (я совместно учить этот курс в C++, но пытается сделать все для себя в ObjC)

001: #import <Foundation/Foundation.h> 
002: #include <assert.h> 
003: 
004: @interface Datagram : NSObject 
005: { 
006:   int dgId; 
007: } 
008: -(id)initWithDatagramType:(int)datagramType; 
009: -(void)dealloc; 
010: -(NSString *)description; 
011: @property (readonly) int dgId; 
012: @end 
013: 
014: @implementation Datagram 
015: @synthesize dgId; 
016: - (NSString *)description { 
017:   return [NSString stringWithFormat: @"Datagram: dgId:", dgId]; 
018: } 
019: 
020: -(id)initWithDatagramType:(int)datagramType { 
021:   self = [super init]; 
022:   if (!self) return self; 
023:   dgId = datagramType; 
024:   return self; 
025: } 
026: 
027: -(void)dealloc { 
028:   NSLog(@"dealloc datagram: %d",dgId); 
029:   [super dealloc]; 
030: } 
031: @end 
032: 
033: // Pretend sequence of packet ID's coming from a sonar 
034: int testSeq[] = { 
035:   3, 12, 4, 19, 8, 
036:   2, 2, 2, 2, 2, 2, 2, 2, 2, 9, 
037:   2, 2, 2, 2, 9, 
038:   2,2,2,2,9, 
039:   1,2,3,4,5,6,7,8,9, 
040:   11,12,13,14,15,16,17,18,19, 
041:   3, 
042:   0 // End of sequence/array sentinal 
043: }; 
044: 
045: @interface DatagramFile : NSObject <NSFastEnumeration> 
046: { 
047:  // No ivars 
048: } 
049: -(id)init; 
050: @end 
051: 
052: @implementation DatagramFile 
053: -(id)init { 
054:  self = [super init]; 
055:  if (!self) return self; 
056:  // NOP 
057:  return self; 
058: } 
059: 
060: - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len 
061: { 
062:   NSLog(@"In countByEnumeratingWithState: stackbuf: %p, count: %d", stackbuf, len); 
063:   NSLog(@"\t state struct: state=%d %p %p", state->state, state->itemsPtr, state->mutationsPtr); 
064:   if (stackbuf) { 
065:     NSLog(@"***INSPECTING STACKBUF\n"); 
066:     for(int i=0;i<1000 && stackbuf[i]!=0;i++) { 
067:       NSLog(@"Stackbuf %d: %p",i,stackbuf[i]); // What should I do with stackbuf[i]? 
068:     } 
069:   } 
070:   if (0 == state->state) {   
071:     NSLog(@"Initializing loop"); 
072:     assert(0==state->itemsPtr); 
073:     state->itemsPtr = malloc(sizeof(id)*16); 
074:     memset(state->itemsPtr, 0, sizeof(id)*16); 
075:   } elseif (0==len) { 
076:     // Will this get called if the call uses break inside the for loop? 
077:     NSLog(@"Finished loop. cleanup"); 
078:     free(state->itemsPtr); 
079:     state->itemsPtr = 0; 
080:   return 0; 
081:   } 
082:   state->mutationsPtr = (unsigned long *)self; // Tell the caller that the file has not changed 
083:   
084:   NSUInteger count=0; 
085:   for (; count < len && testSeq[state->state]!=0; count++, state->state++) { 
086:     NSLog(@"Creating datagram of type %d state: %d count %d",testSeq[state->state], state->state, count); 
087:     Datagram *dg = [[Datagram alloc] initWithDatagramType:testSeq[state->state]]; 
088:     state->itemsPtr[count] = dg; 
089:     [dg autorelease]; 
090:   } 
091:   NSLog(@"countByEnumeratingWithState read %d datagrams. state->state: %d",count, state->state); 
092:   return count; 
093: } 
094: @end // implementation DatagramFile 
095: 
096: int main (int argc, const char * argv[]) { 
097:  NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 
098:   
099:  DatagramFile *df = [[DatagramFile alloc] init]; 
100:  for (Datagram *dg in df) { 
101:   NSLog(@"About to read datagram in for"); 
102:   NSLog(@" Datagram type: %d", [dg dgId]); 
103:  } 
104:   
105:  NSLog(@"about to drain pool"); 
106:  [pool drain]; 
107:  NSLog(@"pool drained. ready for winter"); 
108:  return 0; 
109: }

ответ

1

Odd; Я уверен, что раньше была более полная документация в The Objective-C Programming Language. В любом случае, чтобы ответить на ваш конкретный вопрос: state->itemsPtr - это то место, где вы положили фактический результат. stackbuf и len предоставить временное пространство, которое вы можете использовать для этой цели, но вам не требуется. Например, если ваша коллекция использует прямой массив ссылок на объекты C, вы можете напрямую поместить это в state->itemsPtr и таким образом вернуть все объекты за один раз.

Как для реализации:

  • Она никогда не бывает полезно посмотреть на первоначальное содержание stackbuf.
  • Вместо malloc() буфера, используйте stackbuf. Используйте len вместо жестко закодированного 16.
  • «Будет ли это вызвано, если вызов использует разрыв внутри цикла for?» Нет, это не так. Нет надежной возможности очистки.
  • Как вы говорите, вызывающий может сливать пул авторезистов в цикле. В этой ситуации нет полностью «безопасного» способа борьбы с временными объектами. Все, что вы можете сделать, это документ, который вызывающий не должен сливать пул, созданный за пределами итерации в рамках итерации. На практике это вряд ли будет проблемой.
+0

Спасибо. У меня есть более чистая версия кода, размещенного сейчас: http://schwehr.org/blog/attachments/2010-08/using-NSFastEnumeration.m –

+0

Точно, какой тип данных будет иметь «прямой массив объектов массива объектов» ? Является ли это массивом «unsigned long» или вы можете сделать массив c с использованием типа object-c 'id'? –

+0

@ Давид: да, вы можете это сделать. Фактически, вы должны реализовать 'NSFastEnumeration'. Вот что такое 'stackBuf' и' state-> itemsPtr'. –

Смежные вопросы