NSView удалить некоторые подпредставления из суперпредставления - PullRequest
3 голосов
/ 01 ноября 2011

У меня есть программа размещения объявлений, которая создает страницы (страница класса NSView) и на каждой странице размещает поля и желоба (больше NSViews), а затем рекламу (класс объявления NSView). Приложение автоматически размещает объявления из источника базы данных, ища подходящее место для заполнения на каждой странице. Затем у пользователя есть возможность переместить объявления со страницы 4 на страницу 2. Кроме того, у него есть возможность вручную показывать объявления или иметь автоматический поток приложений, при условии, что только что перемещенное объявление окажется в 0 /. 0 x / y местоположение, а затем остальные будут перетекать в любое доступное пространство, перемещаясь на следующую страницу, если на текущей странице нет места (из-за объявления, которое вы только что переместили).

Что я делал, так это собирал все страницы (сами подвиды NSView, называемые masterpage), а затем просматривал их, чтобы получить все их подвиды в массив. Переберите этот массив, отфильтровав поля и желоба, и, если это реклама, удалите ее из суперпредставления. Моей мыслью было начать с чистой страницы и заменить всю рекламу. Проблема в том, что я продолжаю получать эту ошибку:

Collection <NSCFArray: 0x1078900> was mutated while being enumerated.

Я использую этот код:

//loop through all the pages
    for(NSView* thisPage in masterPageSubViews) { 

        //get all the ads on this page
        NSArray* thisPageSubviews = [thisPage subviews];
        for(NSView* thisPageSubview in thisPageSubviews) { 
            if ([[thisPageSubview className] isEqual:@"Ad"]) { 
                [thisPageSubview removeFromSuperview];
            }
        }
    }

Полагаю, я не понимаю, почему я получаю эту ошибку. Я думал, что объекты в массиве были отделены от объектов, создаваемых в цикле.

Поскольку количество объявлений на каждой странице является динамическим, как я могу убрать их из их суперпредставления без использования массива?

Ответы [ 5 ]

7 голосов
/ 01 ноября 2011

Как говорится в сообщении об ошибке, вы не можете изменить содержимое массива при его быстром перечислении.removeFromSuperview удаляет представление из массива subviews его суперпредставления (это сложное предложение для чтения!).Это означает, что вы изменяете массив во время его перечисления.

Возможно, есть лучший способ, но у вас может быть NSMutableArray, который вы заполняете представлениями рекламы, затем, когда вы закончите, вы можете заставить их удалить себя из суперпредставления (непроверенный код, введитев браузере!)

NSMutableArray *viewsToRemove = [[NSMutableArray alloc] init];
for(NSView* thisPage in masterPageSubViews) 
{           
    //get all the ads on this page         
    NSArray* thisPageSubviews = [thisPage subviews];         
    for(NSView* thisPageSubview in thisPageSubviews)              
        if ([thisPageSubview isMemberOfClass:[Ad class]]) 
            [viewsToRemove addObject:thisPageSubview];                                 
}         
[viewsToRemove makeObjectsPerformSelector:@selector(removeFromSuperview)];
[viewsToRemove release];  
5 голосов
/ 24 сентября 2012

Ответ выше довольно дорогой, зачем создавать объекты, когда вы можете избежать этого?И вы можете сделать то же самое с меньшим количеством кода.

while([[superView subviews] count] > 0) {
    [[[superView subviews] objectAtIndex:0] removeFromSuperview];
}

РЕДАКТИРОВАТЬ: я новичок в Objective C и Какао, поэтому я не знаю, будет ли это работать без ARC, как я никогдакодирование без него.

0 голосов
/ 19 февраля 2015

Если проверка класса является проблемой (и в первоначальном вопросе она была), то, опять же, без перечислителя, проблему можно решить из серверной части:

NSArray *subs = [myView subviews];
for(NSInteger i=[subs count]-1; i>0; i--){
    if([[subs[i] className]isEqual:@"nameOfClassToDelete"]){
        [subs[i] removeFromSuperviewWithoutNeedingDisplay];
    }
}

У меня есть этот код на практике, он работает: -)

0 голосов
/ 11 ноября 2014

По крайней мере, начиная с 10.10, вы можете использовать быстрое перечисление для подпредставлений, так как оно возвращает копию.

[view.subviews enumerateObjectsUsingBlock:^(NSView * subview, NSUInteger idx, BOOL *stop) {
    [subview removeFromSuperview];
}];
0 голосов
/ 04 января 2014
if([[yourView subviews] count] > 0) {
    [[[yourView subviews] objectAtIndex:0] removeFromSuperview];
}

Good Luck !!!
...