0

I have an iPhone app connects to a server using OAuth. On success, it fetches the a user from the server. Again, upon success, it adds an item to the array of objects that populates the table view. Here is the code that does this:

- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{
    if (editing) {
        [super setEditing:YES animated:YES];

        self.backButton = self.navigationItem.leftBarButtonItem;

        UIBarButtonItem *leftButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(signInWithCatapult)];
        self.navigationItem.leftBarButtonItem = leftButton;
    } else {
        [super setEditing:NO animated:YES];

        self.navigationItem.leftBarButtonItem = self.backButton;
    }
}

- (void)signInWithCatapult
{
    [self signOut];

    GTMOAuth2Authentication *auth = [self catapultAuthenticaiton];
    NSURL *authURL = [NSURL URLWithString:@"https://oauth.lvh.me:3000/oauth/authorize"];
    GTMOAuth2ViewControllerTouch *viewController;
    viewController = [[GTMOAuth2ViewControllerTouch alloc] initWithAuthentication:auth
                                                                 authorizationURL:authURL
                                                                 keychainItemName:kCatapultKeychainItemName
                                                                         delegate:self
                                                                 finishedSelector:@selector(viewController:finishedWithAuth:error:)];

    [[self navigationController] pushViewController:viewController animated:YES];
}

- (GTMOAuth2Authentication *)catapultAuthenticaiton
{
    NSURL *tokenURL = [NSURL URLWithString:kDoorkeeperTokenURL];
    NSString *redirectURI = @"https://catapultcentral.com/iOSClientCallback";

    GTMOAuth2Authentication *auth;

    auth = [GTMOAuth2Authentication authenticationWithServiceProvider:@"Catapult Central"
                                                             tokenURL:tokenURL
                                                          redirectURI:redirectURI
                                                             clientID:kDoorkeeperClientID
                                                         clientSecret:kDoorkeeperClientSecret];

    return auth;
}

- (void)signOut
{

}

- (void)viewController:(GTMOAuth2ViewControllerTouch *)viewController
      finishedWithAuth:(GTMOAuth2Authentication *)auth
                 error:(NSError *)error
{
    if (error != nil) {
#if DEBUG
        NSLog(@"ERROR: %@", error);
#endif
    } else {
        NSURL *url = [NSURL URLWithString:@"https://api.lvh.me:3000/api/users/me"];
        NSURLRequest *request = [NSURLRequest requestWithURL:url];
        GTMHTTPFetcher *fetcher = [GTMHTTPFetcher fetcherWithRequest:request];
        [fetcher setAuthorizer:auth];
        [fetcher beginFetchWithDelegate:self didFinishSelector:@selector(currentUserFetcher:finishedWithData:error:)];
    }
}

- (void)currentUserFetcher:(GTMHTTPFetcher *)fetcher
          finishedWithData:(NSData *)data
                     error:(NSError *)error
{
    if (error != nil) {
#if DEBUG
        NSLog(@"ERROR: %@", error);
#endif
    } else {
        NSLog(@"Before: %@", self.accounts);
        [self.tableView beginUpdates];
        [self.accounts addObject:@"Success!!!"];
        [self.tableView endUpdates];
//        [self.tableView reloadData];
        NSLog(@"After %@", self.accounts);
    }
}

It's in the currentUserFetcher:finishedWithData:error: method that I add the object to the self.accounts mutable array. Now if I use this code it doesn't work:

[self.tableView beginUpdates];
[self.accounts addObject:@"Success!!!"];
[self.tableView endUpdates];

It fails at the line [self.tableView endUpdates]; with the following error message:

2013-03-28 08:56:21.040 Catapult for iOS[55012:c07] *** Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-2380.17/UITableView.m:1054

And on the endUpdates line, XCode is complaining saying Thread 1: breakpoint 1.3. Now, if I use this code, it works normally:

[self.accounts addObject:@"Success!!!"];
[self.tableView reloadData];

Now I suspect that it is failing because I add an object to the self.accounts instance variable but I don't actually add the cell. So my question is: How do I add a cell to the tableView from the currentUserFetcher:finishedWithData:error: method?

Robert Audi
  • 8,019
  • 9
  • 45
  • 67

1 Answers1

0

If you just override this method:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;

Calling [UITableView reloadData] should just work itself out. The UITableViewController will just ask the amount of data (cells) that are there (using "tableView:numberOfRowsInSection:") and is requesting the Cell for every indexPath using the first mentioned method.

Niek van der Steen
  • 1,413
  • 11
  • 33
  • As I specified in the question, if I use `[self.tableView reloadData]` it works fine. The idea is to use `[self.tableView beginUpdates]` and `[self.tableView endUpdates]` but if I use that in my code it doesn't work... – Robert Audi Mar 28 '13 at 09:16
  • And why do you want to design it that way ? As far as I know, it's not a common way of designing table views .. – Niek van der Steen Mar 28 '13 at 09:21
  • When I authenticate the app using OAuth, I essentially add an account. After I add the account, I need to add a table cell to the table view. If I added the account straight away, I could have designed it differently, but I need to add the table cell dynamically. I there is another way of designing the app to achieve what I want to do, then you're welcome to suggest anything better. I designed it this way because I don't know better... – Robert Audi Mar 28 '13 at 09:30
  • So, what's wrong adding the new object to your data-set and calling 'reloadData' ? – Niek van der Steen Mar 28 '13 at 09:32
  • From what I read, when calling the `reloadData` method, the adding of the cell is not animated. That's why I would rather use `beginUpdates` and `endUpdates`. – Robert Audi Mar 28 '13 at 09:36
  • I must admit that I am not sure if it will animate. I believe it does. Anyway, even then I'd just use reloadData in combination with Core Animation. – Niek van der Steen Mar 28 '13 at 09:37
  • I do some research on Core Animation but really, I'd rather use `beginUpdates` and `endUpdates` since the animations come out of the box. – Robert Audi Mar 28 '13 at 09:42
  • That solution seems overly bloated, what's the overhead doing that? – Robert Audi Mar 28 '13 at 10:06