UITableView reloadData вызывает прекращение работы всех анимаций - PullRequest
1 голос
/ 25 февраля 2011

Хорошо, это действительно странный вопрос, поэтому я собираюсь разметить происходящее, а затем дать код. Для моего примера я собираюсь использовать статическое количество просмотров, 2.

Основы
У меня есть UIPageControl с X добавлено много подпредставлений. В каждом подпредставлении viewDidLoad представляет собой NSXMLParse для захвата канала XML. Как только канал получен, он анализируется и таблица перезагружается с использованием разобранного массива. На каждом экране также есть кнопка «Настройки». Когда нажата кнопка «Настройки», запускается UIModalTransitionStyleCoverVertical: Animated: YES, и UINavigationController перемещается в представление с полной анимацией. Отклонение также показывает анимацию, возвращающуюся к предыдущему виду. Если вы находитесь в настройках, вы можете PushViews два уровня глубины (слайд в анимации).

Проблема
Случайное количество времени, когда приложение создается и запускается (Не возобновлено) , когда вы нажимаете кнопку Настройки, анимация не возникает. Все функционально, кроме основной анимации удалены. DismissModal просто переключается на предыдущий экран. PushView в NavigationController больше не имеет анимации, просто появляется следующий вид.

Если вы выйдете из приложения (Kill Process) и перезапустите его, оно может нормально работать какое-то время, но в какой-то момент, когда вы нажмете кнопку Настройки, оно потеряет все анимации.

Подробности
Я начал с Apples PageControl Apples для основы. Он создает динамическое количество просмотров на основе пользовательских настроек.

- (void)awakeFromNib
{   
    kNumberOfPages = 2;

    // view controllers are created lazily
    // in the meantime, load the array with placeholders which will be replaced on demand
    NSMutableArray *controllers = [[NSMutableArray alloc] init];
    for (int i = 0; i < kNumberOfPages; i++)
    {
        [controllers addObject:[NSNull null]];
    }

    self.viewControllers = controllers;

    // a page is the width of the scroll view
    scrollView.pagingEnabled = YES;
    scrollView.contentSize = CGSizeMake(scrollView.frame.size.width * kNumberOfPages, scrollView.frame.size.height);
    scrollView.showsHorizontalScrollIndicator = NO;
    scrollView.showsVerticalScrollIndicator = NO;
    scrollView.scrollsToTop = NO;
    scrollView.delegate = self;

    pageControl.numberOfPages = kNumberOfPages;
    pageControl.currentPage = 0;

    // pages are created on demand
    // load the visible page
    // load the page on either side to avoid flashes when the user starts scrolling
    [self loadScrollViewWithPage:0];
    [self loadScrollViewWithPage:1];
}


- (void)loadScrollViewWithPage:(int)page
{
    if (page < 0)
        return;
    if (page >= kNumberOfPages)
        return;

    // replace the placeholder if necessary
    SecondViewController *controller = [viewControllers objectAtIndex:page];
    if ((NSNull *)controller == [NSNull null])
    {
        controller = [[SecondViewController alloc] initWithPageNumber:page];
        [viewControllers replaceObjectAtIndex:page withObject:controller];
        [controller release];
    }

    // add the controller's view to the scroll view
    if (controller.view.superview == nil)
    {
        CGRect frame = scrollView.frame;
        frame.origin.x = frame.size.width * page;
        frame.origin.y = 0;
        controller.view.frame = frame;
        [scrollView addSubview:controller.view];
    }

}

Когда генерируется каждое представление, оно запускает NSXMLParse в своем viewDidLoad. До этого момента все работало нормально. Оба представления генерируются, и вы можете провести между ними.

Если вы нажмете кнопку настроек

- (IBAction)settingsButtonPressed:(id)sender;
{
    SettingsViewController *settingsViewController = [[SettingsViewController alloc] initWithNibName:@"SettingsViewController" bundle:nil];

    UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:settingsViewController];  

    navigationController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;

    [self presentModalViewController:navigationController animated:YES];

    [settingsViewController release];
    [navigationController release];
}

На этом этапе SettingsViewController появляется в поле зрения. Тем не менее, иногда он скользит с правильной анимацией. В других случаях он просто появляется, и все последующие основные анимации нарушаются, пока процесс не будет перезапущен.

Я прошел и проверил все NSXMLParse и сузил проблему до одной строки. В каждом из моих подпредставлений есть tableView, после разбора XML я создал массив с результатами и выполнил [self.tableview reloadData]. Если я закомментирую эту строку, то таблица, очевидно, загружается только пустой, но у нее нет проблем с анимацией.

- (void)parserDidEndDocument:(NSXMLParser *)parser
{   
    NSMutableArray *tableData = ARRAY_GENERATED_HERE;
    [self.tableView reloadData];
}

My Testing
Отмечу, что из моих тестов все в порядке, если для kNumberOfPages установлено значение 1 вместо 2. Создается только 1 представление, сбоев анимации не происходит. Добавьте второй вид, обычно при открытии настроек пять раз, он будет давать сбой.

Все еще не пришли к решению, но оно имеет отношение к [tableView reloadData]. Любое понимание было бы замечательно.

Даниил указал на то, что имеет смысл.

Мой XML извлекается в viewDidLoad с использованием:

[NSThread detachNewThreadSelector:@selector(parseXMLFileAtURL:) toTarget:self withObject:path];

- (void)parseXMLFileAtURL:(NSString *)URL
{   
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 

    stories = [[NSMutableArray alloc] init];

    //you must then convert the path to a proper NSURL or it won't work
    NSURL *xmlURL = [NSURL URLWithString:URL];

    // here, for some reason you have to use NSClassFromString when trying to alloc NSXMLParser, otherwise you will get an object not found error
    // this may be necessary only for the toolchain
    rssParser = [[NSXMLParser alloc] initWithContentsOfURL:xmlURL];

    // Set self as the delegate of the parser so that it will receive the parser delegate methods callbacks.
    [rssParser setDelegate:self];

    // Depending on the XML document you're parsing, you may want to enable these features of NSXMLParser.
    [rssParser setShouldProcessNamespaces:NO];
    [rssParser setShouldReportNamespacePrefixes:NO];
    [rssParser setShouldResolveExternalEntities:NO];

    [rssParser parse];

    [pool release];
}

1 Ответ

2 голосов
/ 25 февраля 2011

Из вашего комментария вы сказали, что запускаете парсер в фоновом потоке ... UIKit не является потокобезопасным, и я подозреваю, что это вызывает ваши проблемы ... попробуйте сделать вызов reloadData в основном потоке, для этого используйте NSObjects executeSelectorInMainThread ...

[self performSelectorOnMainThread:@selector(operationComplete) withObject:nil waitUntilDone:false];
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...