roozbubu
roozbubu

Reputation: 1176

Poor UIScrollView Performance with Many Subviews

I am building a simple app which displays a users Contacts with photos like this -

App

The contacts are each a positioned subview, with another subview inside containing a UIImageView to generate the images w/rounded corners and a UILabel.

Scrolling becomes rather choppy on both iPhone 4/4s and iPhone 5, however, even with only 6-7 contacts. Also, the choppyness seems to be constant. It doesn't matter if they have 8 contacts or 500 contacts, it doesn't get worse or better either way.

Does anybody know why this might be? The algorithm that generated this grid can be seen below. Are there any specific properties on the UIScrollView I haven't set, etc?

- (void) generateContactGrid
{
    CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(self.addressBook);
    CFIndex nPeople = ABAddressBookGetPersonCount(self.addressBook);


    int peopleInARow = 0;
    int maxPeopleInARow = 3;
    int positionFromTop = 20;
    int IMAGE_SIZE = 70;
    float animationOffset = .5;
    float animationOffsetChange = .3;
    float animationDuration = .5;
    int scaleOffset = 40;
    int screenWidth = 320;
    int startingPositionFromLeft = 26;
    int positionFromLeft = startingPositionFromLeft;
    int topOffset = 40;
    int leftOffset = 26;
    int numberOfRows = 0;


    UIView *contactContainer;
    UIImage* image;
    CALayer *l;
    NSString *name;
    NSString *lastName;
    NSString *firstName;
    UIImageView *newimageview;
    UILabel *label;
    UIView *contactImageContainer;



    for ( int i = 0; i < nPeople; i++ )
    {
        ABRecordRef person = CFArrayGetValueAtIndex(allPeople, i);
        firstName = (__bridge_transfer NSString*)ABRecordCopyValue(person,kABPersonFirstNameProperty);
        lastName = (__bridge_transfer NSString*)ABRecordCopyValue(person, kABPersonLastNameProperty);
        name = [NSString stringWithFormat:@"%@ %@", firstName, lastName];

        if(ABPersonHasImageData(person)){
            NSLog(@"Current Contact Being Generated: %@", name);
            image = [UIImage imageWithData:(__bridge NSData *)ABPersonCopyImageData(person)];

            NSLog(@"Contact's Position From Left: %i", positionFromLeft);
            newimageview = [[UIImageView alloc] initWithFrame:CGRectMake(-scaleOffset/2, -scaleOffset/2, IMAGE_SIZE+scaleOffset, IMAGE_SIZE+scaleOffset)];
            newimageview.contentMode = UIViewContentModeScaleAspectFit;
            [newimageview setImage: image];
            contactContainer = [[UIView alloc] initWithFrame:CGRectMake(positionFromLeft, positionFromTop + 20, IMAGE_SIZE, 200)];
            contactImageContainer = [[UIView alloc] initWithFrame:CGRectMake(0, 0, IMAGE_SIZE, IMAGE_SIZE)];
            contactImageContainer.clipsToBounds = YES;

            l = [contactImageContainer layer];
            [l setMasksToBounds:YES];
            [l setCornerRadius:IMAGE_SIZE/2];

            [l setBorderWidth:0.0];
            [l setBorderColor:[[UIColor colorWithRed:234.0/255.0 green:234.0/255.0 blue:234.0/255.0 alpha:.6] CGColor]];


            [contactImageContainer addSubview:newimageview];

            [contactContainer addSubview:contactImageContainer];

            label =  [[UILabel alloc] initWithFrame: CGRectMake(0, IMAGE_SIZE + 10, IMAGE_SIZE, 20)];
            label.text = firstName;
            label.backgroundColor = [UIColor colorWithRed:0/255.0 green:0/255.0 blue:0/255.0 alpha:0];
            label.textColor = [UIColor whiteColor];
            [label setTextAlignment:NSTextAlignmentCenter];
            [label setFont:[UIFont fontWithName:@"Arial-BoldMT" size:14]];
            [contactContainer addSubview:label];


            contactContainer.alpha = 0;

            [UIView beginAnimations:nil context:nil];
            [UIView setAnimationDuration:animationDuration];
            [UIView setAnimationDelay:animationOffset];
            animationOffset+= animationOffsetChange;
            [UIView setAnimationCurve:UIViewAnimationCurveEaseOut];

            contactContainer.alpha = 1;
            CGRect temp = contactContainer.frame;
            temp.origin.y = positionFromTop;
            contactContainer.frame = temp;

            [UIView commitAnimations];

            if(peopleInARow >= 2){
                positionFromTop += IMAGE_SIZE + topOffset;
                peopleInARow = 0;
                positionFromLeft = startingPositionFromLeft;
                numberOfRows++;

            } else {
                peopleInARow += 1;
                positionFromLeft += IMAGE_SIZE + leftOffset;
            }

            [self.scrollView addSubview:contactContainer];
            [self.scrollView bringSubviewToFront:contactContainer];


        }

    }

    NSLog(@"%i", numberOfRows);

    self.scrollView.contentSize = CGSizeMake(screenWidth, 150 * numberOfRows);

}

Upvotes: 1

Views: 1662

Answers (1)

anon
anon

Reputation:

Use Instruments to measure what exactly makes your app slow. Everything else is just guessing.

But I will guess anyways. This most likely is the masking you apply to your UIImageViews. Try disabling that and see if it is still slow (and by see I mean measure, of course). If that is indeed the cause there are two things you can try. First you can set the shouldRasterize property of the masked layer and see if that actually is enough. This could make things worse though if your layers get changed a lot. The other option would be to render those masked pictures with Core Graphics instead of using layers.

Upvotes: 2

Related Questions