After getting my Stanford course Presence 2 assignment running smoothly, I am tackling Presence 3 which adds threading. My presence app first displays a list of twitter users in a navigation controller. Tapping an accessary button on a user pushes a detail form that contains a tableView that displays all of the user's status messages.
I have successfully converted my PersonListViewController to load the list of users using a NSOperationQueue. Now I want to us the same technique to load the status messages on the detail form when PersonDetailViewController gets pushed onto the stack.
The user's are contained in a dictionary of user dictionaries, and the detail form only needs the user that was tapped. So in my PersonListViewController's accessoryButtonTappedForRowWithIndexPath method I am passing that user dictionary to the pushed PersonDetailViewController...
I am starting the NSOperationQueue in the numberOfRowsInSection of the detail view as that is the only place I could find that I was insured that the person dictionary had been set properly.
I have the NSOperationQueue methods set up just like I did in the list view that works fine.
It runs through the first pass with zero rows fine and displays the view. I know that the run after the operation completes is running because I have traced the numberOfRowsInSection section and can see it returning 19 rows for the user I am testing. I also am adjusting the row height in heightForRowAtIndexPath and watched it correctly fetch each status message to determine the row height.
After heightForRowAtIndexPath is called for the last (19th) time, the app crashes with "EXC_BAD_ACCESS". cellForRowAtIndexPath does not get called. I am stumped as to how to debug this as I don't know where to look after the heightForRowAtIndexPath method is called.
What else happening between heighForRowAtIndexPath and cellForRowAtIndexPath that could be causing the crash? cellForRowAtIndexPath is being called for the first time after the operation completes because the first time through I am setting the row count to zero.
Is there something else with my code that might be causing the problem? Build and Analyze does not report any problems.
Do I need to do something with the NSOperationQueue I created in my PersonListViewcontroller?
The only thing I am doing different from the operation on the list view is starting the operation from the numberOfRowsInSection method instead of the viewWillAppear method which I cannot do because the person dictionary has not been set yet when this method is called. Same holds for the viewDidLoad method.
Thanks for any help,
John
I have successfully converted my PersonListViewController to load the list of users using a NSOperationQueue. Now I want to us the same technique to load the status messages on the detail form when PersonDetailViewController gets pushed onto the stack.
The user's are contained in a dictionary of user dictionaries, and the detail form only needs the user that was tapped. So in my PersonListViewController's accessoryButtonTappedForRowWithIndexPath method I am passing that user dictionary to the pushed PersonDetailViewController...
Code:
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath{
self.navigationController.navigationBarHidden = NO;
PersonDetailViewController *personDetailViewController = [[PersonDetailViewController alloc] initWithNibName:@"PersonDetailViewController" bundle:nil];
[self.navigationController pushViewController:personDetailViewController animated:YES];
PersonTableCell *cell = (PersonTableCell *) [tableView cellForRowAtIndexPath:indexPath];
personDetailViewController.person =[tweetsData objectAtIndex:indexPath.row];
//tweetsData is the dictionary of user dictionaries and person is the user dictionary on the detail view
[personDetailViewController release];
[cell release];
}
I am starting the NSOperationQueue in the numberOfRowsInSection of the detail view as that is the only place I could find that I was insured that the person dictionary had been set properly.
Code:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if(dict){ //dict is the status message dictionary and is being set in the NSOperationQueue
return dict.count/2;
}else {
[self beginLoadingStatus];
return 0;
}
}
I have the NSOperationQueue methods set up just like I did in the list view that works fine.
Code:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
operationsQueue2 = [[NSOperationQueue alloc] init];
[operationsQueue2 setMaxConcurrentOperationCount:1];
}
return self;
}
- (void)beginLoadingStatus{
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(loadStatus) object:nil];
[operationsQueue2 addOperation:operation];
[operation release];
}
- (void)loadStatus{
NSDictionary *dictTemp = [person statusDict]; // [[NSDictionary alloc] initWithDictionary:person.statusDict];
NSLog(@"LoadStatus: %@", dictTemp);
[self performSelectorOnMainThread:@selector(didFinishLoadingStatusWithResults:) withObject:dictTemp waitUntilDone:NO];
[dictTemp release];
dictTemp = nil;
}
- (void)didFinishLoadingStatusWithResults:(id)results{
dict = [[NSDictionary alloc] initWithDictionary:results];
[detailTableView reloadData];
}
It runs through the first pass with zero rows fine and displays the view. I know that the run after the operation completes is running because I have traced the numberOfRowsInSection section and can see it returning 19 rows for the user I am testing. I also am adjusting the row height in heightForRowAtIndexPath and watched it correctly fetch each status message to determine the row height.
Code:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
CGFloat height;
if(dict){
NSString *text = [dict valueForKey:[NSString stringWithFormat:@"text%i", indexPath.row]];
UIFont *font = [UIFont fontWithName:@"Helvetica" size:13.0];
CGSize withinSize = CGSizeMake(280, 1000);
CGSize size = [text sizeWithFont:font constrainedToSize:withinSize lineBreakMode:UILineBreakModeWordWrap];
if(size.height > 49){
height = 81 + (size.height - 49);
}else {
height = 81;
}
}else {
height = 81; //this should never happen as if there is no dict then number of rows will be zero
}
return height;
}
After heightForRowAtIndexPath is called for the last (19th) time, the app crashes with "EXC_BAD_ACCESS". cellForRowAtIndexPath does not get called. I am stumped as to how to debug this as I don't know where to look after the heightForRowAtIndexPath method is called.
What else happening between heighForRowAtIndexPath and cellForRowAtIndexPath that could be causing the crash? cellForRowAtIndexPath is being called for the first time after the operation completes because the first time through I am setting the row count to zero.
Is there something else with my code that might be causing the problem? Build and Analyze does not report any problems.
Do I need to do something with the NSOperationQueue I created in my PersonListViewcontroller?
The only thing I am doing different from the operation on the list view is starting the operation from the numberOfRowsInSection method instead of the viewWillAppear method which I cannot do because the person dictionary has not been set yet when this method is called. Same holds for the viewDidLoad method.
Thanks for any help,
John