С NSPointerArray, как перебирать непрозрачные указатели?

Я недавно обнаружил эти классы, как NSMapTable а также NSPointerArray, которые работают как традиционные коллекции, но также позволяют хранить слабые ссылки или простые старые указатели Си. К сожалению, похоже, что вы не можете использовать for...in синтаксис для перебора не-NSObject указатели. Например:

typedef struct Segment {
    CGPoint bottom, top;
} Segment;
...
NSPointerArray *segments = [[NSPointerArray alloc] 
                                 initWithOptions:NSPointerFunctionsOpaqueMemory];
...
Segment *s = malloc(sizeof(Segment));
[segments addPointer: s];
...
for (Segment *s in segments) {   // nope...

Компилятору не нравится эта последняя строка. Ошибка:

Тип элемента селектора 'Segment *' (также известный как struct Segment * ') не является допустимым объектом

Итак, мне нужно сделать это?

for (int i=0, len=segments.count; i<len; i++) {
    Segment *seg = [segments pointerAtIndex:i];
    ...

Это не конец света, но я просто хочу убедиться.

2 ответа

(Это может быть больше теоретического интереса.) NSPointerArray соответствует NSFastEnumeration протокол, это только for (id object in collection) языковая конструкция, которую нельзя использовать с произвольными указателями, которые не являются указателями Objective-C.

Но вы можете получить целую кучу указателей из массива, вызвав NSFastEnumeration метод countByEnumeratingWithState:objects:count: непосредственно. Это немного сложно, потому что этот метод не должен заполнять предоставленный буфер (как объяснено здесь: как внутри цикла работает внутренне - Цель C - Основа).

Вот простой пример того, как это будет работать:

__unsafe_unretained id objs[10];
NSUInteger count = [segments countByEnumeratingWithState:&state
                                                 objects:objs count:10];

// Now state.itemsPtr points to an array of pointers:
for (NSUInteger i = 0; i < count; i++) {
    Segment *s = (__bridge Segment *)state.itemsPtr[i];
    NSLog(@"%p", s);
}

Так что это не поможет сделать код проще, и вы, вероятно, захотите придерживаться своего явного цикла.

Но для больших массивов это может повысить производительность, поскольку указатели "выбираются" в пакетном порядке из массива, а не каждого указателя в отдельности.

Синтаксис for (... in ...) в этом случае не будет работать, потому что Segment - это структура, а не объект Objective C. Ваш второй цикл должен работать.

Другие вопросы по тегам