سؤال

I'm testing my app currently especially on an iPhone 4s. And some simple UI tasks seem laggy and delayed, sutch as selecting an image in a collection view or changing the state of a UI checkbox. Is there some better way to do this? Do I need to do here something asynchronous? If something is changed an attribute in CoreData gets changed, but can this be that slow?

CollectionView (Image names are all saved in an array on viewdidload):

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *identifier = @"IconCell";

    IconSelectionCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];

    cell.iconImageView.image = [UIImage imageNamed:[self.icons objectAtIndex:indexPath.row]];

    return cell;
}

#pragma mark Collection View Delegate methods
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
    self.mainCategory.icon = [self.icons objectAtIndex:indexPath.row];
}

And the UISwitch for example:

- (IBAction)liveBudgetSwitched:(id)sender
{
    self.spendingCategory.liveBudget = [NSNumber numberWithBool: self.liveBudgetSwitch.on];
}
هل كانت مفيدة؟

المحلول 2

Yes I did. And the lags are due to the NSFetchedResultsController constantly monitoring even when my view is not visible. I just used my property I've used for all user driven changes in my table view to stop the controller from listening when my view is not on the screen:

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    self.suspendAutomaticTrackingOfChangesInManagedObjectContext = YES;
}

-(void)viewDidDisappear:(BOOL)animated
{
    [super viewDidDisappear:animated];
    self.suspendAutomaticTrackingOfChangesInManagedObjectContext = YES;
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    self.suspendAutomaticTrackingOfChangesInManagedObjectContext = NO;
}


#pragma mark - NSFetchedResultsControllerDelegate
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller
{
    if (self.suspendAutomaticTrackingOfChangesInManagedObjectContext) return;

    [self.tableView beginUpdates];
}

- (void)controller:(NSFetchedResultsController *)controller
  didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
           atIndex:(NSUInteger)sectionIndex
     forChangeType:(NSFetchedResultsChangeType)type
{
    if (self.suspendAutomaticTrackingOfChangesInManagedObjectContext) return;

    switch(type) {
        case NSFetchedResultsChangeInsert:
            [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeDelete:
            [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}


- (void)controller:(NSFetchedResultsController *)controller
   didChangeObject:(id)anObject
       atIndexPath:(NSIndexPath *)indexPath
     forChangeType:(NSFetchedResultsChangeType)type
      newIndexPath:(NSIndexPath *)newIndexPath
{
    if (self.suspendAutomaticTrackingOfChangesInManagedObjectContext) return;

    switch(type) {
        case NSFetchedResultsChangeInsert:
            [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeDelete:
            [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeUpdate:
            [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeMove:
            [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
            [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
    if(self.suspendAutomaticTrackingOfChangesInManagedObjectContext) return;

    NSLog(@"Controller did change content");
    [self.tableView endUpdates];
}

نصائح أخرى

With that code is hard to help you. It can be so many things. Maybe your images are way bigger than they should be, maybe your cell has shadow in one label or in the background, who knows?

Therefore, you need to find out the problem first.

In this case you can open instruments and analyze if the problem is CPU or GPU.

You can know if the problem is CPU using the Time Profiler and for the GPU you can use Core Animation.

In the time profiler try to check where the most CPU is being spent. You can use some options to help you focus on your code. You can show objective-c only and hide system libraries.

In Core Animation you have a bunch of options that you can use to check some problems you might have. This options are:

  • Color Blended Layers - Highlights where you have several layers on top of each other and the GPU needs to blend those
  • Color hits green and misses red - If it is green you are fine, if it is red then you aren't caching your images and those images are being regenerated a lot of times (it can happen when you have shadows, for instance)
  • Color copied images - if it shows blue then the core animation is sending a copy of the image to the render server when it should be sending a pointer
  • Flash Updated Regions - it shows yellow when the view is redrawn
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top