Search code examples
iosobjective-cdelegatesblock

How do I delay execution of a delegate method of one protocol until the delegate method of another protocol has completed execution?


In the .m file ClassroomCollectionViewController, I have the following instance variable declared:

@implementation ClassroomCollectionViewController
{
    NSMutableArray *students;
}

This array is populated in the following delegate method of the NSURLConnectionDataDelegate protocol, which ClassroomCollectionViewController implements.

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    if (connection == _getStudentsEnrolledInClassConnection)
    {
        // Parse the JSON that came in
        NSError *error;
        NSArray *jsonArray = [NSJSONSerialization JSONObjectWithData:_receivedData options:NSJSONReadingAllowFragments error:&error];

        if (jsonArray.count > 0)
        {
            students = [[NSMutableArray alloc] init];

            // Populate the students array
            for (int i = 0; i < jsonArray.count; i++)
            {
                Student *studentInClass = [Student new];

                studentInClass.name = jsonArray[i][@"name"];
                studentInClass.profile = jsonArray[i][@"profile"];
                studentInClass.profileImageName = jsonArray[i][@"profile_image_name"];

                [students addObject:studentInClass];
            }
        }
    }
}

In the following delegate method of another protocol, namely the UICollectionViewDelegate, the students array populated above is used to construct the individual cells of the collection view.

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    ClassmateCollectionViewCell *myCell = [collectionView
       dequeueReusableCellWithReuseIdentifier:@"ClassmateCell"
       forIndexPath:indexPath];

    UIImage *image;
    long row = [indexPath row];

    image = [UIImage imageNamed:[students[row] profileImageName]];

    myCell.imageView.image = image;
    myCell.classmateNameLabel.text = [students[row] name];

    return myCell;
}

The problem is that the students array is not yet populated by the time that the second of the two delegate methods above executes, which results in there being no data for the cells in the collection view to display.

The obvious solution to this problem is to delay the execution of the second method until the first one has finished executing (thus ensuring that the students array will be populated by the time the cells in the collection view are constructed). But I couldn't for the life of me figure out how to make this so in this particular context - since I have no control over when the second delegate method is invoked. I have considered using blocks and multithreading in order to solve this, but have failed at coming up with a solution that is relevant for this specific problem.

Could anyone point me in the right direction?

Thanks very much, Jay


Solution

  • Try this, connect an IBOutlet to collection view and

    in your connectionDidFinishLoading: method

    - (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    
       //All other codes for populating `students` array
    
       [self.collectionView reloadData];
    }