1

I'm implementing a "search as you type" search with a core data DB. It's working great with NSFetchedRequestController. But now, I have gotten a feature request to arrange the results by distance from the user(it's a shop list). Say the user write "e" into the search, there are about 7000 results, the iOS device takes between 2-3 second to order them by distance, and in the meantime the UI is stuck. I thought about sending the sort request to a different thread, but then what will I show the user? also, what happens if I send a request and then he type another letter? if he types and deletes a couple of times I will have many requests on many threads taking up computing power.

Any ideas with solving this problem?

Yoav Schwartz
  • 2,017
  • 2
  • 23
  • 43
  • 1
    Try to limit the fetch request. You don't need all the 7000 results at that time. You can lazy load the other part while user scrolling. – Boran Apr 02 '14 at 12:20
  • The request is lazy loaded to like 30 results as a time, but theres no way to get the closest stores without having all the stores.. – Yoav Schwartz Apr 02 '14 at 13:05
  • You can give both fetch limit and a sort descriptor to the fetch request so you don't need the all results for sorting. – Boran Apr 02 '14 at 13:23
  • As far as a I know a sort descriptor can only take a name of a column, the user location changes, so I could not have a column in the database that has the distance of the user from the shop, all I have is the shops location. correct me if I'm wrong? – Yoav Schwartz Apr 02 '14 at 13:41
  • 1
    You're right about that but you can still box your results with predicates for less objects. This SO question can help you. http://stackoverflow.com/questions/2176127/core-data-and-core-location – Boran Apr 02 '14 at 13:53
  • A box sound like A good way to set the number of results down a little bit but I'm not sure the customer would approve, however, your answer led me to some important info I didn't think about, when looking to know which one is closest, it's a waste of energy calculating the distance, calculating the difference in lat/lang is good enough and will save me a lot of processing power, thanks. – Yoav Schwartz Apr 02 '14 at 14:10
  • 1
    @YoavSchwartz another optimization, you don't have to have the distance, you can just as well sort by the distance squared. – David Berry Apr 02 '14 at 15:58
  • @David forgive my lack of math/location skills, but how is the distance squared more efficient? – Yoav Schwartz Apr 03 '14 at 07:20
  • 1
    The distance between two points is estimated as sqrt(delta lat ^ 2 + delta long ^ 2). Calculating sqrt is fairly expensive, but if all you're doing is sorting, you don't need to take the sqrt. – David Berry Apr 03 '14 at 14:51

2 Answers2

0

First of all - analyse what is the most problematic part of your code via Instruments -> Time Profiler. Maybe you have problem inside the code, which can be resolved by rewriting. If it is not helps, I suggest you such things: 1) easiest - remove feature "search while typing" :) 2) make delay between begin search and typing in 1 second - so while user typing you don't search, and then if user stop typing, you do it. 3) change DB model - (for example add some regions for shops, and if user in the region, search for shops only in the region. Just look more closer do your DB model and thing how you can improve it) 4) search in background and show activity indicator while it searching

Vitalii Gozhenko
  • 9,220
  • 2
  • 48
  • 66
0

There are a few things you can do to optimize the user experience here.

One option is to present the user with a loading indicator (e.g. https://github.com/jdg/MBProgressHUD), and create an NSOperation for the sort, which you can process in the background.

An NSOperationQueue here would have the benefit of being able to cancel the task, for example if the user continues to type extra letters in.

For example:

// Interface

@property (nonatomic, strong) NSOperationQueue *sortQueue;

// Implementation 

self.sortQueue = [[NSOperationQueue alloc] init];
[self.sortQueue addOperationWithBlock:^{
    //Sort results here

    dispatch_async(dispatch_get_main_queue(), ^{
        //Update UI here
    });
}];

If the user entered more text, you can cancel the pending sort by doing:

[self.queue cancelAllOperations];

And queueing a new sort.

dzl
  • 908
  • 11
  • 32
  • I'll try it, the GSD is a lot more useful than I thought, don't know why I had something against it. – Yoav Schwartz Apr 02 '14 at 13:08
  • 3
    Note that cancelAllOperations isn't going to be as useful here as you think. `[NSOperation cancel]` doesn't actually stop the operation, but rather it depends on the operation to cooperatively stop itself. Unless your sorting operation periodically checks isCancelled it's still going to run to completion. It will, however, prevent lots of operations from being queued up, as the operations that haven't yet started will be cancelled before they start. – David Berry Apr 02 '14 at 15:52
  • Another option to consider is to not immediately fire the request when they type a character, instead (re)start a timer every time they type a character and only start the sort when the timer elapses (and they stopped typing) – David Berry Apr 02 '14 at 15:55