0

I'd like to create an UISearchBar function, which gets called like the search in the App Store: Execute the function (NSURLConnection) after a few seconds (NSTimer) the user did finish typing and just one time for this period.

Does anyone have an idea?

EDIT

    self.currentTaskID = self.currentTaskID + 1;
    NSInteger taskID = self.currentTaskID;

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), queue, ^{
        if (taskID == self.currentTaskID)
        {
            NSMutableURLRequest *request_CH3 = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://website.com/search.php?term=%@", replaceWhiteSpace]]
                                                               cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
                                                           timeoutInterval:30.0];

            [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];

            authConnection_CH3 = [[NSURLConnection alloc] initWithRequest:request_CH3 delegate:self];
        }
    });
filou
  • 1,609
  • 5
  • 26
  • 53
  • 1
    You sure it's called on a timer?? Not a key press event? – PaulG Nov 07 '12 at 20:51
  • 1
    It's not a timer, searchbarcontroller has a delegate: `-(BOOL)searchDisplayController:shouldReloadTableForSearchString:` to handle filtering search as the user types – mkral Nov 07 '12 at 20:59
  • The search does automatically show the results in the UISearchDisplayController. No key press event needed. – filou Nov 07 '12 at 21:01

3 Answers3

3

I recently made an answer for similar question, you can find it here

Basically you can queue your searches with delay and dismiss any previously scheduled search if new comes in within specified period.

Community
  • 1
  • 1
Tomasz Zabłocki
  • 1,326
  • 7
  • 14
  • Thank you, Tomasz. But your Code looks way to difficult for me :) I am not familiar with GCD. Do you have a good toturial? – filou Nov 07 '12 at 22:15
  • 1
    Please take a look at this great tutorial about [GCD](http://www.raywenderlich.com/4295/multithreading-and-grand-central-dispatch-on-ios-for-beginners-tutorial) – Tomasz Zabłocki Nov 07 '12 at 22:46
  • ok Tomasz, I've tried to use your code (please have a look above) but it seems to be stuck. – filou Nov 08 '12 at 10:45
  • `NSInteger *taskID` this shouldn't be pointer, make it `NSInteger taskID`. `currentTaskID = self.currentTaskID +1;` should be `self.currentTaskID = self.currentTaskID + 1;` – Tomasz Zabłocki Nov 08 '12 at 11:16
  • Also `initWithRequest` returns immediately and will inform your delegate in the future when data is received so it's not right to call `showSearchResults` immediately but after data is actually downloaded. – Tomasz Zabłocki Nov 08 '12 at 11:25
  • ok. but ´NSInteger taskID´ returns: incompatible pointer to integer initializing 'NSInteger' with expression of type 'NSInteger' – filou Nov 08 '12 at 11:26
  • How did you declare your currentTaskID @property? It should be `@property(assign) NSInteger currentTaskID;` – Tomasz Zabłocki Nov 08 '12 at 11:27
  • made all the changes, but the connection stucks in loading (network activity indicator does not stop spinning. Please take a look above for my changes. – filou Nov 08 '12 at 11:33
  • Do you stop it from spinning? I only see you make it visible, does your NSURLConnectionDelegate stop it? – Tomasz Zabłocki Nov 08 '12 at 11:36
  • Since block passed to dispatch_after will be executed in bg thread, you can download your data synchronously here. Take a look at this [SO accepted answer](http://stackoverflow.com/questions/2069039/error-handling-with-nsurlconnection-sendsynchronousrequest) how to do it. Then after calling `sendSynchronousRequest` stop the network spinner. If you choose asynchronus way here, you need to stop the spinner in your delegate method like `connection:didReceiveData:` where the data is actually received. – Tomasz Zabłocki Nov 08 '12 at 11:41
  • yes Tomasz, I totally agree :). But the connection does not get called at all.. I don't know why. – filou Nov 08 '12 at 11:45
  • What do you mean by that? How do you check it and where? – Tomasz Zabłocki Nov 08 '12 at 11:45
  • connection didReceiveResponse and didReceiveData do no answer to NSLog. When I remove the queue block, it works.. – filou Nov 08 '12 at 11:48
  • Did you change `NSInteger *taskID` to `NSInteger taskID`? – Tomasz Zabłocki Nov 08 '12 at 11:49
  • yes, made all changes you told me. Maybe you try it by yourself. – filou Nov 08 '12 at 11:51
  • I can access my mac in the evening, for now please print `NSLog(@"taskID = %d, self.currentTaskID = %d",taskID, self.currentTaskID)` before calling `if (taskID == self.currentTaskID)` and see what it is printing in the console. – Tomasz Zabłocki Nov 08 '12 at 11:54
  • Console: taskID = 1, self.currentTaskID = 1 – filou Nov 08 '12 at 12:01
  • Is `connection:didFailWithError:` delegate method called, if so what is the error? – Tomasz Zabłocki Nov 08 '12 at 12:03
  • Ok, I know what's going on here. The problem is `dispatch_after` creates bg thread, then you set delegate in that thread, after the block is executed the thread is exiting so the delegate won't be called at all. Please use synchronous request in that case inside a block. – Tomasz Zabłocki Nov 08 '12 at 12:09
  • no, then the spinner would stop and a message would be shown. it starts but does not go on. – filou Nov 08 '12 at 12:14
  • you mean I should make a synchronous connection? no better solution? – filou Nov 08 '12 at 12:16
  • 1
    Synchronous but inside asynchronous block so it will be asynchronous. Right now you make asynchronous block with asynchronous request inside it which I would say isn't the right thing to do. Alternativelly you can try passing `dispatch_queue_get_main()` instead of `queue` to dispatch_after... – Tomasz Zabłocki Nov 08 '12 at 12:19
  • seems logic, yes. I'll give it a try. If it does not work I'll let you know :) – filou Nov 08 '12 at 12:25
  • changed it to dispatch_queue_get_main() and now it works perfectly. Now I have to check all permutations. I'll give you a feedback asap :)) – filou Nov 08 '12 at 12:37
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/19288/discussion-between-filou-and-tomasz-zablocki) – filou Nov 08 '12 at 14:04
1

Instead of using timers to do this, implement the delegate function of the UISearchBar, searchBarTextDidEndEditing or searchBar:textDidChange and then when you are satisfied with the number of characters that the user entered you will start your NSURLConnection request

Omar Abdelhafith
  • 21,163
  • 5
  • 52
  • 56
  • The OP wanted to use a timer to let the user finish typing before doing the search. Otherwise if you have a minimum of 5 character you fire off the search after the user types 5 characters and if they hit a sixth, hen you fire off another request. – Peter Apr 26 '14 at 01:04
1

In the function where you want to call the search function (in your case after clicking)

implement this :

[timer invalidate];
    timer = nil;
    timer = [NSTimer scheduledTimerWithTimeInterval: 3.0 target: self selector: @selector(thefunctionyouwanttocall) userInfo: nil repeats: NO];

this will call your function 3 seconds after the click event

Maurice
  • 1,466
  • 1
  • 13
  • 33