Resolved UITableView didSelectRowAtIndex, trigger segue delay bug

Discussion in 'iOS Programming' started by DennisBlah, Jun 25, 2015.

  1. DennisBlah, Jun 25, 2015
    Last edited: Jul 1, 2015

    DennisBlah macrumors 6502

    DennisBlah

    Joined:
    Dec 5, 2013
    Location:
    The Netherlands
    #1
    Hi all,

    I'm trying to get an tableview to work with different custom cell xib's.
    Based on the section it must become a different cell.

    In the second section there are 2 buttons, 1 is to go to next category and 1 to go back to the main view.
    Now when I tap these buttons once, it will take up to 10-15 seconds before it actually gets triggered.

    If I tap twice it will go straight through.
    There for I did put in a activity indicator. Just so the user knows it is doing something...

    How can I solve this bad response ? It does not occure straight form the beginning.
    Once I moved to second viewcontroller with also a table, and moved back, then this happens.

    I'm using the following code:
    Code:
    (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
      categoryItem *cell = [categoriesTable dequeueReusableCellWithIdentifier: @"catCell"];
    
      if(!cell) {
      [tableView registerNib: [UINib nibWithNibName: @"categoryCell" bundle: nil] forCellReuseIdentifier: @"catCell"];
      cell = [tableView dequeueReusableCellWithIdentifier: @"catCell"];
      }
    
      if(indexPath.section == 0) {
      [cell.theCategory setText: [theCategories objectAtIndex: indexPath.row]];
      [cell.theImage setImage: [UIImage imageNamed: [NSString stringWithFormat: @"s%i.png",(int)[(NSNumber *)[theCategoriesID objectAtIndex: indexPath.row] integerValue]]]];
      } else {
      if(indexPath.row == 0) {
      [cell.theImage setImage: [UIImage imageNamed: @"send.png"]];
      [cell.theCategory setText: @"Send Audit"];
      } else {
      [cell.theImage setImage: [UIImage imageNamed: @"stop.png"]];
      [cell.theCategory setText: @"Back to start"];
      }
      }
    
    
      [cell setSelectionStyle: NO];
    
      return cell;
    }
    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
      return 2;
    }
    
    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
      [categoryActivity setHidden: NO];
      if(indexPath.section == 0) {
      categoryDelegate->curCategory = (int)[(NSNumber *)[theCategoriesID objectAtIndex: indexPath.row] integerValue];
      UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
      UIViewController *nextView = [mainStoryboard instantiateViewControllerWithIdentifier: @"criteriumView"];
      nextView.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
      [self presentViewController: nextView animated:YES completion:nil];
      } else {
      if(indexPath.row == 1) {
      UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
      UIViewController *nextView = [mainStoryboard instantiateViewControllerWithIdentifier: @"mainView"];
      nextView.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
      [self presentViewController: nextView animated:YES completion:nil];
      } else {
      UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
      UIViewController *nextView = [mainStoryboard instantiateViewControllerWithIdentifier: @"sendView"];
      nextView.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
      [self presentViewController: nextView animated:YES completion:nil];
      }
      }
    }
    
    - (NSInteger)tableView: (UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
      if(section == 0)
      return theCategories.count;
      else
      return 2;
    }
    
    
    
    - (CGFloat) tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
      if (section == 0)
      return CGFLOAT_MIN;
      return 35.0f;
    }
    
    - (NSString*) tableView:(UITableView *) tableView titleForHeaderInSection:(NSInteger)section {
      if (section == 0) {
      return nil;
      } else {
      return @" ";
      }
    }
    
    -(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
      UIView *view = [[UIView alloc]init];
      [view setAlpha:0.0F];
      return view;
    }
    



    ----------
    UPDATE
    ----------
    At first I did it like this, calling the next view using transition.
    Code:
    UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
    UIViewController *nextView = [mainStoryboard instantiateViewControllerWithIdentifier: @"mainView"];
    nextView.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
    [self presentViewController: nextView animated:YES completion:nil];
    
    Now I made segue's from all viewcontrollers to eachother with their own identifier, and call the segue by identifier, based on the reply of AxoNeuron, which actually saves a lot of typing and code :)
    Code:
    [self performSegueWithIdentifier: nextViewSegue sender: self];
    
    Triggering the performSegue from a static button, results that the app goes through straight away, but by the didSelectRowAtIndexPath it's waiting for something thats not there! :-/
    The end of the function reached straight away, also after calling performSegue, but it's holding on the next viewcontroller's viewDidLoad. viewWillAppear and viewDidAppear don't get called before the 'timeout' and/or I just randomly tap somewhere randomly once

    Found a simulair topic on stackoverflow, mentioning to use sender: nil for performSegueWithIdentifief, so that the tableview itself wont be included.

    Ofcourse I did that straight away, but still having the same issue..

    After playing around with settings of the segue, I found out that when I use the default segue 'Present Modally' and presentation as 'Full Screen' instead of 'Default' it looks like this is solved.

    But after 2 times, the issue is back

    p.s. updating to 10.10.4 and updating xcode at the moment.

    -------------
    SOLLUTION
    -------------
    since iOS8 it seems to be a bug in the tableViewDidSelectRow function.
    Calling segues from this function's thread queue will cause a delay.

    By forcing the segue to be triggered in the main queue will sove the issue:
    Code:
    dispatch_async(dispatch_get_main_queue(), ^{
      [self performSegueWithIdentifier: @"mySegueIdentifier" sender: nil];
    });
    
    I'm glad this is solved. Then I can finally roll-out the app. :D
     
  2. 1458279 Suspended

    1458279

    Joined:
    May 1, 2010
    Location:
    California
    #2
    Ok, I assume the table is displaying the way you want based on the description of the problem.

    Yet, you've posted the cellForRow code.

    How do you handle the tap(s)?

    This could also be a loading issue, if you run the debugger, where does it take the time? In other words, are you making it load something that takes a long time to load.
    You could put in some NSLog calls and watch it run or put in a text box and display the status when in enters every method. Then just watch as it enters each method call and see which one is taking so long.

    Another issue might be memory management. You could make a new project and have it only do the methods you are calling and see if it works faster.

    Instruments can probably help you with this as well.

    An old trick is to set some NSLogs that display the time and have them all over the place to find out where the slow code is.
     
  3. DennisBlah thread starter macrumors 6502

    DennisBlah

    Joined:
    Dec 5, 2013
    Location:
    The Netherlands
    #3
    Hi KarlJay,

    if you scroll down in my code, you will see I posted every function related to UITableView, incl. didSelectRowAtIndexPath

    In the top and bottom I hit a NSLog, if tapped and finish function.
    Both get shown directly, however it will not present my new viewcontroller untill I randomly tapped somewhere else on the screen :-/ and it will present instantly.
     
  4. 1458279 Suspended

    1458279

    Joined:
    May 1, 2010
    Location:
    California
    #4
    Ok, so it waits for you to tap somewhere else after you've already tapped once?

    In that case, I would run the debugger and see what happens when you tap the 1st time. It sounds like the 1st tap is not getting processed the way you want.

    What else does your program do? Does it have any special gesture handlers or active threads? Does the 1st tap go into the same method, but not get processed? I assume the 1st tap was intended to show the new viewcontroller.
     
  5. DennisBlah thread starter macrumors 6502

    DennisBlah

    Joined:
    Dec 5, 2013
    Location:
    The Netherlands
    #5
    Exactly, the first tap should already have triggered the "[self presentViewController: nextView animated:YES completion:nil];"
    However the function "- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {" is finished and no viewcontroller been presented untill I just randomly press somewhere or again on the same button.

    On the current viewcontroller or the next or previous one there are no special gestures set up or threads.
    On a other view controller, (the very first one, a settings view, and the last view, there I set up a Observer for keyboard shown and hide, to adjust the origin.y of my self.view to make sure that textfield ends up above they keyboard.
    At the viewWillDisapear of these 3 viewcontrollers I remove the observer.

    Further all, the app loads up simple queries with only a few records of a small sqlite database.
    (this all is really small, and really simple queries, like SELECT * FROM audit_round WHERE category = %i (current category set on AppDelegate->curCategory)

    I'm using the AppDelegate as a simple 'navigation' by storing my current category, criterium and the 'database manager' as the database will be checked if exists and setup for first time from AppDelegate. I choose for this way because it was the simplest and easiest way and I always done it like this also in previous projects.

    The only difference here in this project is the tableview that's using multiple costum cells.

    How should I be debugging this? (I'm not quite sure how to debug and stuff, always use NSLog's to find out what's wrong like wrong intepretation of variables, when functions get triggered etc)
     
  6. 1458279 Suspended

    1458279

    Joined:
    May 1, 2010
    Location:
    California
    #6
    Well 1st you need to find out if the 1st touch is actually going into the method. If the 1st touch is going in, what logic path is it following.

    It sound as if the touch is being processed somewhere else and not getting to the method you think it is.

    If it's not getting there on the 1st tap, it could be because you've changed the state of something.

    NSLog works fine for this, but you can also use a step thru in the debugger. You can click on the part of Xcode next to the line of code where you want the debugger to stop, then use the step over button at the top of the debug window. Watch the debugger run thru the code line by line.

    You mentioned different tables, are you using the same delegate for each table? Remember, they can share the same methods. It gets a bit complex, but you have some things that are unique to each instance and some things that are common to all the object instances. This was a sticking point for me when I had multiple pickviewers as they shared some of the same methods.
     
  7. DennisBlah, Jun 26, 2015
    Last edited: Jun 26, 2015

    DennisBlah thread starter macrumors 6502

    DennisBlah

    Joined:
    Dec 5, 2013
    Location:
    The Netherlands
    #7
    Hi Karl,

    no the tableview's have their own delegate on their own UIViewController

    Like mentioned before I added 2 NSLogs like this:
    Code:
    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
      NSLog(@"Tapped");
      [categoryActivity setHidden: NO];
      NSString *nextViewC = nil;
      if(indexPath.section == 0) {
      categoryDelegate->curCategory = (int)[(NSNumber *)[theCategoriesID objectAtIndex: indexPath.row] integerValue];
      nextViewC = @"criteriumView";
      } else {
      if(indexPath.row == 1) {
      nextViewC = @"mainView";
      } else {
      nextViewC = @"sendView";
      }
      }
      if(nextViewC != nil) {
      UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
      UIViewController *nextView = [mainStoryboard instantiateViewControllerWithIdentifier: nextViewC];
      nextView.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
      [self presentViewController: nextView animated:YES completion:nil];
    
      }
      NSLog(@"Finished selectrow");
    }
    
    These logs appear both like.. instantly, but the [self presentViewController.... is being triggered after a 10-15 seconds OR another tap, randomly, does not matter if its on the tableview or not.
     
  8. 1458279, Jun 26, 2015
    Last edited by a moderator: Jun 29, 2015

    1458279 Suspended

    1458279

    Joined:
    May 1, 2010
    Location:
    California
    #8
    Ok, put an NSLog after each line like this:

    Code:
    if(nextViewC != nil) {
    UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
    NSLog(@"One");
    UIViewController *nextView = [mainStoryboard instantiateViewControllerWithIdentifier: nextViewC];
    NSLog(@"Two");
    nextView.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
    NSLog(@"Three");
    [self presentViewController: nextView animated:YES completion:nil];
    NSLog(@"Four");
    That should tell you exactly which call is causing the delay.

    Also, is there any code that runs when the new viewcontroller is about to be presented, maybe something that has a block or completion block or something? Are all your completion blocks nil? IDK how the debugger handles a block that's running on a different thread, so it might be hard to tell.

    BTW, where's the button for marking code in a post, I don't see it so I can't mark the code.
     
  9. DennisBlah thread starter macrumors 6502

    DennisBlah

    Joined:
    Dec 5, 2013
    Location:
    The Netherlands
    #9
    Hi Karl,

    as I mentioned with 2 NSLog's being executed instantly, also happens on your ehm ... 'request' / 'advice'.
    They get executed instantly after my tap.

    All completion blocks are nil indeed. I always use nil ..
    On a viewwillappear I'm already throwing NSlog's in to see in console if it's getting loaded or not.

    Put the code between [ code] and [/ code]
    Now you are mentioning it, I can't find a code button either :D
     
  10. 1458279 Suspended

    1458279

    Joined:
    May 1, 2010
    Location:
    California
    #10
    Ok wait... The NSLog before and after the call are executed but the view doesn't show up until later?

    If that's the case then there's something else that's causing the delay.
    I'd start looking at transitions that maybe you set or are default project wide.
    Check for one of those "after delay" calls that might be hiding somewhere.
    I assume you wrote all the code and aren't using someone else's code that might have a hidden transition block thing.

    From what I gather, you can get the view to come up instantly by doing a tap somewhere. IDK, but do those transition block get interrupted by a tap?

    Just for kicks, I'd to one of those "project clean" things that recompiles everything just to make sure everything is up to date.

    Just to make sure, the view does come up without the tap, but it's delayed by 10+ seconds, and this is when running on the device? What about running on the simulator, same thing?

    The new view that opens, what's inside the viewDidLoad and viewWillLoad? Did you NSLog those too?
     
  11. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #11
  12. 1458279 Suspended

    1458279

    Joined:
    May 1, 2010
    Location:
    California
    #12
    Ahhh, hidden under the "+" button :D Thanks.
     
  13. AxoNeuron macrumors 65816

    AxoNeuron

    Joined:
    Apr 22, 2012
    Location:
    The Left Coast
    #13
    Its a strange issue. Why don't you use segues in the actual storyboard itself? It's a lot simpler to just call [self performSegueWithIdentifier: @"blah"]

    If you need to set properties and such you can set them in the prepareForSegue method and instantiate a reference to the next view controller to set properties using segue.destinationViewController.

    I've never had this issue using segues created using the storyboard. Though I've had cases where it's not possible to use the storyboard and I had to instantiate the view controller programmatically like you've done here. Is it necessary in this case?
     
  14. 1458279 Suspended

    1458279

    Joined:
    May 1, 2010
    Location:
    California
    #14
    I've read several times that anything that can be done in storyboard can be done in code. I'm personally a big fan of doing things in code because that allows you to change things programmatically.

    I actually make it a point to learn how to do many things programmatically, but it might not have an advantage in this case.

    Even if he could use storyboard for the whole thing, there's still an issue of a computer program that isn't working as he want's it to work... and that's a problem that needs to be solved.

    Not to mention, that there might be some setting or bug that can effect something else that can't be solved with storyboard.

    Point: Something is not working properly, some weird delay. We should find out what the bug is and find a solution to it.
     
  15. DennisBlah, Jun 28, 2015
    Last edited: Jun 28, 2015

    DennisBlah thread starter macrumors 6502

    DennisBlah

    Joined:
    Dec 5, 2013
    Location:
    The Netherlands
    #15
    It's 100% my own project and code from scratch, I been doing this much more often in other projects.
    Just somehow it's not responding fine.

    Also in the new viewWillLoad's of other viewcontrollers it's just doing a simple sqlite query, and reload the table on the viewcontroller.
    Also these logs are getting triggered directly after the transition started.

    I partially agree on this one, when you need more custom things like transitions or whatever, you can do it in code directly, like dynamic buttons etc, however with a tableview you can get a far way as well.

    However, the less code you are using should result in a faster application. I'm still learning bit a bit a little more about the storyboard GUI, but this is something

    You are actually right, I will setup the seque's in the storyboard and use them like u mentioned. Will come back later on this.
    The thing is I need to go to different viewcontrollers based on choosen row in tableview :)
     
  16. 1458279, Jun 28, 2015
    Last edited by a moderator: Jun 29, 2015

    1458279 Suspended

    1458279

    Joined:
    May 1, 2010
    Location:
    California
    #16
    Ok, now we may be getting some where...

    Let me guess, this is all on the same thread? You are running an SQLite query on the main thread?

    If you take out the query, does the problem stop?

    Do you know how to dispatch the query to another thread?

    Probably a good idea to put it on another thread anyways, and don't forget the activity indicator.
     
  17. DennisBlah, Jun 29, 2015
    Last edited: Jun 29, 2015

    DennisBlah thread starter macrumors 6502

    DennisBlah

    Joined:
    Dec 5, 2013
    Location:
    The Netherlands
    #17
    I just moved out the presentViewController calls and replaced with performSegue's. The issue remains.

    What do you mean with the same thread?
    This query is just a simple Query, which results in a max of 5 results.

    I do initialize the DBManager one in AppDelegate.
    This will be re-used throughout the app by using:
    Code:
    mainDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
      NSArray *curSettings = [mainDelegate->appData loadDataFromDB: @"SELECT * FROM audit_settings"];
    
    Before moving to the new viewcontroller it does not do anything with the appData (DBManager) anymore, and will do it again once the next view didappear

    By the way, when I put a breakpoint at the start of didSelectRowAtIndexPath like you mentioned before, and I just hit execture, then it does move to the desired viewcontroller in 1 go.


    Somehow just now, it seems after a clean build and clean build folder, (after change to the performSegue functions) it looks like its going alright now.
     
  18. 1458279, Jun 29, 2015
    Last edited by a moderator: Jun 29, 2015

    1458279 Suspended

    1458279

    Joined:
    May 1, 2010
    Location:
    California
    #18
    Ok, 1st off the number of results is not an issue. The only time the number of results becomes an issue is when it comes to the amount of memory the results will use.

    Consider: If you go to the store for only a loaf of bread, the loaf of bread is only the amount of storage. It's the distance to the store, the traffic and the routine you must to through in order to get to and from the store.

    2nd is the amount of memory that your app must get in order to process the query and what memory is open to it at that time. This is also device dependent.

    3rd, it's almost always a good idea to know GCD and how to break down a program into good thread sets, even if it doesn't seem slow on your tests.

    Now that you've cleaned and moved the project, I'd put the code back the way it was in order to see if it was the clean/move that changed things.

    Part of testing is not just testing to see if it works, but stress testing to see how it works in low memory and while other apps are running in the background. This is more important going forward, as Apple has fully embraced multi-tasking.

    Either way, it'll be helpful to others that read this thread, if you'll take the time to post the results. Someone might run into the same problem some day and we're here to help each other.
     
  19. DennisBlah thread starter macrumors 6502

    DennisBlah

    Joined:
    Dec 5, 2013
    Location:
    The Netherlands
    #19
    Sorry I did not make a new project :rolleyes:
    But the issue does still persist but it's not continously now...

    Still I don't understand what you mean with:
    "Let me guess, this is all on the same thread? You are running an SQLite query on the main thread?"

    How should I break down to seperated threads?

    I will be starting with a clean build, without special tableview cells etc. one of these days. And post some results like memory etc.
     
  20. 1458279 Suspended

    1458279

    Joined:
    May 1, 2010
    Location:
    California
    #20
    Your UI has to wait for the query to complete because it's blocking the main thread. Generally you want to move most of the non-UI work from the main thread. Things that go out and process something like pictures, files, data records, server data, etc... tend to slow things down and the UI has to wait for them to complete.

    Move the query to a another thread and put up an activity indicator to let the user know something is going on.

    Remember UI must be on the main thread.

    Have you worked with blocks, threads and GCD ?

    Code Coalition has a great project involving picture filters that show how to do this. I think it might be posted up on GitHub.

    If you don't know about blocks, you'll probably like them, they have great power.
     
  21. DennisBlah thread starter macrumors 6502

    DennisBlah

    Joined:
    Dec 5, 2013
    Location:
    The Netherlands
    #21
    I understand that the UI will wait untill everything in for example, viewwillappear and viewdidappear has finished.
    However the data is local, and returns a array of 5 rows with 3 columns.

    If I put the data manually, or even if I put no data at all, or with a NSTimer that will trigger after 2 seconds when viewdidappear I still got this same weird issue.

    When I even let all viewcontrollers initiate its own 'DBManager' instead of using the one thats already initiated in AppDelegate, I still got the same issue.

    A NSLog before initiating my data, should already be triggered after my didSelectRowAtIndexPath has finished.
    If the UI is done loading, still waiting or whatever.

    It just does not got triggered at all, unless I wait 15 seconds or tap once more.
    (If I tap twice directly, it gets shown instantly as well)

    There must be something else wrong, but I just can't get my head around it.
    This is a plain simple app, nothing hard, time consuming or any math.

    I can even throw it in 1 big viewcontroller which is actually a previous version of this one, which works perfectly, but is such a mess, in the UI and in code that it's hardly maintainable.
     
  22. 1458279 Suspended

    1458279

    Joined:
    May 1, 2010
    Location:
    California
    #22
    Ok, what I said about the thread might not make a difference based on what you say. It's still a good idea, but might not be the issue you have.

    You might have already answered this, but I'll ask again: Do you know exactly what line of code it's pausing at?

    When I ask for the line of code where it's pausing at, I'm talking about digging down to the lowest level you can.

    I was under the impression that the query call was where it paused.

    If that's the case, then can you post or repost the full query code.

    BTW, does it do the same thing if you run on the simulator?
     
  23. DennisBlah thread starter macrumors 6502

    DennisBlah

    Joined:
    Dec 5, 2013
    Location:
    The Netherlands
    #23
    Hi KarlJay,

    I'll just put down the whole code of 2 viewControllers in particulair.
    When I hit the row in categoryView to go back to mainView, it takes up to 15 seconds before it actually goes, and vice versa from mainView to categoryView.

    The graziest part is, it does not pause anywhere. Using the step into code after a breakpoint, I just end up in a whole load of calls in dylib files etc.
    The logs all appear instantly like it suppose.
    Ofcourse except for the logs in the didload, willappear of the next view, these only get called once it's actually triggering the segue... By waiting long time, or tap randomly.

    I'm not sure how to troubleshoot it further to get to know where the issue comes from.
    Hopefully someone here can push me in the right direction.

    CategoryView:
    Code:
    #import "categoryView.h"
    
    @interface categoryView ()
    
    @end
    
    @implementation categoryView
    
      AppDelegate *categoryDelegate;
      NSMutableArray *theCategories;
      NSMutableArray *theCategoriesID;
    
      @synthesize categoriesTable;
    
    - (void)viewDidLoad {
      NSLog(@"Category view did load");
      [super viewDidLoad];
      // Do any additional setup after loading the view.
    }
    
    - (void)didReceiveMemoryWarning {
      [super didReceiveMemoryWarning];
      // Dispose of any resources that can be recreated.
    }
    -(void)viewWillAppear:(BOOL)animated {
      NSLog(@"View will appear!");
    }
    
    -(void)viewDidAppear:(BOOL)animated {
      NSLog(@"Category view did appear");
      categoryDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
       
      theCategories = [[NSMutableArray alloc] initWithObjects: nil];
      theCategoriesID = [[NSMutableArray alloc] initWithObjects: nil];
      NSArray *categories = [categoryDelegate->appData loadDataFromDB: @"SELECT * FROM audit_categories"];
      NSInteger i_id = [categoryDelegate->appData.arrColumnNames indexOfObject: @"cat_id"];
      NSInteger i_name = [categoryDelegate->appData.arrColumnNames indexOfObject: @"cat_name"];
      if(categories.count > 0) {
      for(int a=0; a<categories.count; a++) {
      [theCategories addObject: [[categories objectAtIndex: a] objectAtIndex: i_name]];
      [theCategoriesID addObject: [[categories objectAtIndex: a] objectAtIndex: i_id]];
      }
      [categoriesTable reloadData];
      } else {
      UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"5S Audit app v3.0" message:@"No categories found!" delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil];
      [alert show];
      }
    }
    
    
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
      categoryItem *cell = [categoriesTable dequeueReusableCellWithIdentifier: @"catCell"];
       
      if(!cell) {
      [tableView registerNib: [UINib nibWithNibName: @"categoryCell" bundle: nil] forCellReuseIdentifier: @"catCell"];
      cell = [tableView dequeueReusableCellWithIdentifier: @"catCell"];
      }
       
      if(indexPath.section == 0) {
      [cell.theCategory setText: [theCategories objectAtIndex: indexPath.row]];
      [cell.theImage setImage: [UIImage imageNamed: [NSString stringWithFormat: @"s%i.png",(int)[(NSNumber *)[theCategoriesID objectAtIndex: indexPath.row] integerValue]]]];
      } else {
      if(indexPath.row == 0) {
      [cell.theImage setImage: [UIImage imageNamed: @"send.png"]];
      [cell.theCategory setText: @"Send Audit"];
      } else {
      [cell.theImage setImage: [UIImage imageNamed: @"stop.png"]];
      [cell.theCategory setText: @"Back to start"];
      }
      }
       
       
      [cell setSelectionStyle: NO];
    
      return cell;
    }
    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
      return 2;
    }
    
    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
      NSLog(@"Did selected row!");
      NSString *nextViewSegue = nil;
      if(indexPath.section == 0) {
      categoryDelegate->curCategory = (int)[(NSNumber *)[theCategoriesID objectAtIndex: indexPath.row] integerValue];
      nextViewSegue = @"criteriumSegue";
      } else {
      if(indexPath.row == 1) {
      nextViewSegue = @"mainSegue";
      } else {
      nextViewSegue = @"sendSegue";
      }
      }
      NSLog(@"Next view: %@", nextViewSegue);
      if(nextViewSegue != nil)
      [self performSegueWithIdentifier: nextViewSegue sender: self];
       
      NSLog(@"Did select end...");
    }
    
    - (NSInteger)tableView: (UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
      if(section == 0)
      return theCategories.count;
      else
      return 2;
    }
    
    
    
    - (CGFloat) tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
      if (section == 0)
      return CGFLOAT_MIN;
      return 35.0f;
    }
    
    - (NSString*) tableView:(UITableView *) tableView titleForHeaderInSection:(NSInteger)section {
      if (section == 0) {
      return nil;
      } else {
      return @" ";
      }
    }
    
    -(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
      UIView *view = [[UIView alloc]init];
      [view setAlpha:0.0F];
      return view;
    }
    
    @end
    
    
    MainView:
    Code:
    #import "mainView.h"
    
    @interface mainView ()
    
    @end
    
    @implementation mainView
    
      @synthesize overlayView;
    
      BOOL isKeyboard_main = NO;
      BOOL movedView_main = NO;
      UITextField *activeField_main;
    
    
      AppDelegate *mainDelegate;
    
      @synthesize auditType;
      NSMutableArray *auditType_id;
      NSMutableArray *auditTypes;
    
    
      @synthesize auditLocation;
      @synthesize auditArea;
      @synthesize setupAudit;
      @synthesize OKbutton;
    
    - (void)viewDidLoad {
      [super viewDidLoad];
      // Do any additional setup after loading the view, typically from a nib.
    }
    
    - (void)didReceiveMemoryWarning {
      [super didReceiveMemoryWarning];
      // Dispose of any resources that can be recreated.
    }
    
    -(void)viewWillAppear:(BOOL)animated {
      NSLog(@"View will appear!");   
    }
    
    -(void)viewDidAppear:(BOOL)animated {
      NSLog(@"View did appear!");
      auditType_id = [[NSMutableArray alloc] initWithObjects: nil];
      auditTypes = [[NSMutableArray alloc] initWithObjects: nil];
      mainDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
      NSArray *curSettings = [mainDelegate->appData loadDataFromDB: @"SELECT * FROM audit_settings"];
      if(curSettings.count == 0) {
      UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"5S Audit app v3.0" message:@"This is the first time you open the 5S Audit app!\nYou first need to setup the app for the 5S Audit results" delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil];
      [alert show];
       
      UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
      UIViewController *nextView = [mainStoryboard instantiateViewControllerWithIdentifier: @"settingsView"];
      nextView.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
      [self presentViewController: nextView animated:YES completion:nil];
      }
       
      NSArray *currentAudit = [mainDelegate->appData loadDataFromDB: @"SELECT * FROM audit_current ORDER BY id"];
      if(currentAudit.count > 0) {
      NSInteger i_location = [mainDelegate->appData.arrColumnNames indexOfObject: @"cur_location"];
      NSInteger i_area = [mainDelegate->appData.arrColumnNames indexOfObject: @"cur_area"];
      NSInteger i_type = [mainDelegate->appData.arrColumnNames indexOfObject: @"cur_type"];
       
      [auditLocation setText: [[currentAudit firstObject] objectAtIndex: i_location]];
      [auditArea setText: [[currentAudit firstObject] objectAtIndex: i_area]];
      mainDelegate->curLocation = auditLocation.text;
      mainDelegate->curArea = auditArea.text;
      mainDelegate->curType = (int)[(NSNumber *)[[currentAudit firstObject] objectAtIndex: i_type] integerValue];
    
      UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"5S Audit app v3.0" message:[NSString stringWithFormat: @"Currently you still have a audit round pending.\nFor: %@  at area: %@\nDo you wish to continue or start a new audit?",[[currentAudit firstObject] objectAtIndex: i_location],[[currentAudit firstObject] objectAtIndex: i_area]] delegate:self cancelButtonTitle:@"New audit" otherButtonTitles: @"Continue",nil];
      [alert show];
      }
       
      NSArray *typesQ = [mainDelegate->appData loadDataFromDB: @"SELECT * FROM audit_types ORDER BY type_id"];
      if(typesQ.count > 0) {
      NSInteger i_type = [mainDelegate->appData.arrColumnNames indexOfObject: @"type_name"];
      NSInteger i_id = [mainDelegate->appData.arrColumnNames indexOfObject: @"type_id"];
      for(int a=0; a<typesQ.count; a++) {
      [auditType_id addObject: [[typesQ objectAtIndex: a] objectAtIndex: i_id]];
      [auditTypes addObject: [[typesQ objectAtIndex: a] objectAtIndex: i_type]];
      }
      [auditType reloadData];
      } else {
      UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"5S Audit app v3.0" message:@"No audit types found!?!" delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil];
      [alert show];
      }
       
    }
    
    
    -(IBAction)auditSetupDone:(id)sender {
      if(auditLocation.text.length > 1 && auditArea.text.length > 1) {
      [setupAudit setHidden: YES];
      [OKbutton setHidden: YES];
       
      [auditType setHidden: NO];
      } else {
      UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"5S Audit app v3.0" message:@"You must fill in a location and area for your audit!" delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil];
      [alert show];
      }
    }
    
    
    
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
      tableCell *cell = [auditType dequeueReusableCellWithIdentifier: @"theCell"];
       
      if(!cell) {
      [tableView registerNib: [UINib nibWithNibName: @"tableCell" bundle: nil] forCellReuseIdentifier: @"theCell"];
      cell = [tableView dequeueReusableCellWithIdentifier: @"theCell"];
      }
      cell.textLabel.text = [auditTypes objectAtIndex: [indexPath row]];
      [cell setSelectionStyle: NO];
      return cell;
    }
    
    
    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    NSLog(@"Did tap!");
      [mainDelegate->appData truncatetable: @"audit_current"];
      NSString *setupQ = [NSString stringWithFormat: @"INSERT INTO audit_current (cur_type, cur_location, cur_area) VALUES (%i,'%@','%@')", (int)[(NSNumber *)[auditType_id objectAtIndex: indexPath.row] integerValue], auditLocation.text, auditArea.text];
      [mainDelegate->appData executeQuery: setupQ];
       
      mainDelegate->curType = (int)[(NSNumber *)[auditType_id objectAtIndex: indexPath.row] integerValue];
       
      mainDelegate->curLocation = auditLocation.text;
      mainDelegate->curArea = auditArea.text;
    NSLog(@"Trigger segue");
      [self performSegueWithIdentifier: @"categorySegue" sender: self];
    NSLog(@"Finish didSelectRow!");
    }
    
    - (NSInteger)tableView: (UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
      return [auditTypes count];
    }
    
    -(UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section{
      UIView *view = [[UIView alloc]init];
      [view setAlpha:0.0F];
      return view;
    }
    
    
    -(BOOL)textFieldShouldReturn:(UITextField *)textField {
      [textField endEditing: YES];
      return YES;
    }
    
    
    - (void)alertView:(UIAlertView *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
      if(buttonIndex == 0) {
      [mainDelegate->appData truncatetable: @"audit_current"];
      [auditLocation setText: @""];
      [auditArea setText: @""];
      NSFileManager *fileManager = [NSFileManager defaultManager];
      NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
      NSString *documentsDir = [paths objectAtIndex:0];
      for(int a=1; a<11; a++)
      for(int b=1; b<11; b++)
      for(int c=1; c<3; c++) {
      NSString *tPhoto = [NSString stringWithFormat: @"%i_%i_%i.jpg", a,b,c];
      [fileManager removeItemAtPath:[documentsDir stringByAppendingPathComponent: tPhoto] error:nil];
      }
      } else {
      //audit_settings
      NSArray *settingsQ = [mainDelegate->appData loadDataFromDB: @"SELECT my_firstname, my_surname, my_email, to_name, to_email, to_topic FROM audit_settings"];
      mainDelegate->curAuditor = [NSString stringWithFormat: @"%@ %@", [[settingsQ firstObject] objectAtIndex: 0], [[settingsQ firstObject] objectAtIndex: 1]];
      mainDelegate->curMailFrom = [[settingsQ firstObject] objectAtIndex: 2];
      mainDelegate->curMailTo = [[settingsQ firstObject] objectAtIndex: 3];
      mainDelegate->curMailToMail = [[settingsQ firstObject] objectAtIndex: 4];
      mainDelegate->curMailToTopic = [[settingsQ firstObject] objectAtIndex: 5];
       
       
      [self performSegueWithIdentifier: @"categorySegue" sender: self];
      }
    }
    
    @end
    
     
  24. 1458279 Suspended

    1458279

    Joined:
    May 1, 2010
    Location:
    California
    #24
    It's hard to see any problems with just the code, but knowing exactly which line it's paused on will help.

    If you set a breakpoint, you should be able to track down the exact line as well as trace where it goes. Here's a tutorial about debugging:

    http://www.raywenderlich.com/28289/debugging-ios-apps-in-xcode-4-5

    I'd set a breakpoint (click on the bar in front of the line of code), then step thru each line of code.

    Another option is to comment out query part of the code and have the second vies show a simple list of numbers. That would tell you if the query is the problem or not.

    Using the process of elimination, you can comment out line by line until the problem goes away, but I think stepping thru the code with the debugger would show where the program is when it pauses.

    A given thread always has a point of control, the point of control must be somewhere, the debugger should show you exactly where the control is when it pauses.
     
  25. DennisBlah thread starter macrumors 6502

    DennisBlah

    Joined:
    Dec 5, 2013
    Location:
    The Netherlands
    #25
    Hi KarlJay,

    I know with breakpoints and the step into code, I can go through the code line by line incl. the dylib files. like send object etc.
    Funnies part of this is, when I'm going through line by line, eventually it will just jump to the mainView because going through lines took longer than the 'delay'.

    I know that it's something with viewDidLoad, because when the segue is 'triggered' the mainView gets into viewDidLoad.
    After that the didSelectRow from categoryView ends.

    After that, nothing happens. why and how to debug that?

    I can keep clicking endlessly but never find the issue as I don't see whats going on when it's in the delay...
    If I'm debugging this manually, I don't see the delay thus I can't say where the issue is.
     

Share This Page