0

What I am trying to achieve is simple, from first thinking though. I found it hard to handle at last.

I would like to push a table view as a selection list, user select one cell and the cell string was sent to the previous view as selected string, simple huh??

See two pictures first

select housing, then push to the next view

select one cell in this view

what bothers me is that:

I would like to provide (at least) two buttons, one on the left is back button auto-generated by navigation controller, and the right one is for editing. And the navigation controller is defaulted to have two buttons (from my knowledge). So there is no place for "Done" button, which is supposed for user to tap and then confirm and pop to the previous view. So, when the user tap a cell, "Wearing" for example, I would like the following to happen, automatically and visually SEEable for user:

  1. user can SEE that "Housing" cell is unmarked
  2. then user can SEE that "Wearing" cell is marked
  3. then after a little time gap (say 0.2 second), pop to the previous view and update the selection, automatically.

At first I thought it's easy but it's definitely not. Here is my code for doing it, but working wired

    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{

dispatch_queue_t queue=dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0ul);

dispatch_async(queue, ^{
    //unmark previous cell
    if (selectedIndexPath!=nil) {
        [[self.tableView cellForRowAtIndexPath:selectedIndexPath]setAccessoryType:UITableViewCellAccessoryNone];
    }
    selectedIndexPath=indexPath;


        //get the selected cell to mark
        UITableViewCell *cell=[self.tableView cellForRowAtIndexPath:indexPath];
        [cell setAccessoryType:UITableViewCellAccessoryCheckmark];

        dispatch_sync(dispatch_get_main_queue(), ^{
            //wait a little
            [NSThread sleepForTimeInterval:0.2];
            //return to previous view
            NSLog(@"here.........");
            if ([objectToUpdateCategory respondsToSelector:@selector(updateCategoryTo:withSelectedIndexPath:)]) {
                NSLog(@"sending.......... update info");
                [objectToUpdateCategory updateCategoryTo:cell.textLabel.text withSelectedIndexPath:selectedIndexPath];
                NSLog(@"sent update info");
            }
            [self.navigationController popViewControllerAnimated:YES];

    });

});

The tricky thing is that if I put [self.navigationController popViewControllerAnimated:YES]; to the last, the view will not visually update the unmark and mark step and go back to the previous view immediately. At first, when I didn't consider the unmark thing, the “queue" stuff in code can do the mark step visually before popping back, but sometimes not working. I don't know if my code is correct, actually I don't quite understand this queue tech from apple. But I'm pretty sure it has something to do with NSThread / queue or else that handle concurrency. I've checking Apple documents for a whole day and found no direct answer.

Hope someone could help me on this, thanks in advance :)

JimZ
  • 1,182
  • 1
  • 13
  • 30
  • 1
    You are updating the UI on a background thread. You shouldn't do that. UIKit is not thread-safe. – Marcin Kuptel May 12 '13 at 08:49
  • Well....I kinda give up what I'm trying to do, I would like to add the cell with button texted "Edit" at the bottom of the whole table view. – JimZ May 12 '13 at 11:31

2 Answers2

1

To "after a little time gap (say 0.2 second), pop to the previous view", use the performSelector:withObject:afterDelay: methods or one of its variants, e.g.:

[self performSelector:@selector(delayedPop) withObject:nil afterDelay:0.2];

and put the popViewControllerAnimated in the delayedPop method, e.g.:

-(void)delayedPop{
    [self.navigationController popViewControllerAnimated:YES];
}
bobnoble
  • 5,794
  • 3
  • 25
  • 32
  • wow, great answer, I think thi is what I want! I didn't notice there is such performSelector:afterDelay !!!!! Thanks bobnoble – JimZ May 13 '13 at 00:22
0

First of all, as I wrote in my comment, you shouldn't update the UI on a background thread. This will cause a lot of problems, including the UI not being updated immediately. In your case you don't need to use dispatch_async or dispatch_sync at all. What I would do is create a property in the view controller that displays the categories table view:

@property (nonatomic, weak) id<CategoryControllerDelegate> delegate;

When you push the category controller on the stack you set your expense controller as the delegate. Then, when the user makes a selection in the category controller, you call a method on the delegate (defined in a protocol), for example the one in your code sample:

@protocol CategoryControllerDelegate<NSObject>
@optional
- (void) updateCategoryTo: (NSString*) category withSelectedIndexPath: (NSIndexPath*) path;
@end

After that you pop the current view controller off the stack.

Marcin Kuptel
  • 2,674
  • 1
  • 17
  • 22
  • Hi marcinkuptel, thanks for your answer. I checked your answer but that's not I expected. But yes updating UI behaves so randomly in runtime, like not updating immediately. I already use delegate to transfer category selection result and it works fine no matter the unmark & mark step is updated or not. What I want to achieve is show the user the "unmark & mark" step. So I'm not trying to update the UI and make the value transfer :) anyway, thank you all the same – JimZ May 12 '13 at 11:23