Insert items into alphabetical sections in tableview - cocoa-touch

So, I have an array of various names and I have populated the table with section headers
A-Z.
Is it correct to find the first char of my data and then subsequently put it in the correct section, or is there a way to do it using a faster method.
I believe what I am doing is wrong as I am thinking of making an A array for example and then find every element starting with 'A' and insert it inside. But this is a bit crazy as then, I would need to create A-Z arrays which I seriously do not think that is the correct way.
I'm sorry if this is posted in the documentations but I don't seem to be able to find it.
Any help from you guys in this matter?

Well I actually did it this way, too and I don't see any reasons why this shouldn't be done, as it decouples the fetching / sorting process from refreshing the tableview, which in turn keeps loading and scrolling the tableview smooth.
Having A-Z arrays is not a big issue memorywise since they're just holding references to your data objects anyway and not the data itself. But it allows you fast access to your data objects without the need for expensive comparison operations.
Just make sure your arrays are kept up to date if data objects are added or deleted.

Related

Dict vs Record in elm

While implementing a simple app I ran into the problem of trying to update a nested record. I found a solution online but it really seems like a whole lot of bloated code.
As I was looking for alternatives I found Dictionaries. This seem like a solution to that problem -- If I use a dictionary inside of a record I can avoid all that bloated code and get nested updates.
Seeing dictionaries and records next to each other made me wonder, why would I use a record instead of a dictionary, or vice versa? The two seem really similar to me, so I am not sure I see the advantage of one or the other. Of course I can see that there is a difference in syntax, but is that all ?
I learned somewhere that the access time complexity of Dict is O(log(n)) -- does it do a binary search on the keys ? -- but I can't find the access time complexity for record, but I am wondering if that is O(1) and that is one of the advantages.
Either way, they both seem to map to 1 single data structure in other languages (e.g Python's dictionaries, JS objects, Java hash-tables), why do we need two in elm ?
Dicts and records might seem very similar when coming from JavaScript, but in a statically typed language they are actually very different. I think just about the only property they have in common is that they are both key-value containers.
The biggest differences, I think, are that Dicts are homogeneous, meaning values must be of the same type, and "dynamically" keyed and sized, meaning keys are not statically checked (ie. at compile-time) and that key-value pairs can be added at runtime. Records on the other hand includes the key names and value types in the record type, which means they can hold values of different types, but also can't have keys added or removed at runtime without changing the type itself.
The benefits of easily being able to insert and update a Dict is something you pay for when you try to get it back out. Dict.get returns a Maybe which you'll then have to handle, because the type doesn't give any guarantee that it contains anything at all. You also won't get a compiler error if you mistype the name of a key.
Overall, a Dict forsakes most of the benefits of static typing. I think a good rule of thumb is that if you know the key names, you should most likely go with records. If you don't, go with Dict.
You also seem about right regarding performance, but I think that's a secondary concern. Record access should be equivalent to accessing the elements of an array by index, since so much information is known at compile time that it can essentially be compiled down to a fixed-size array.

setFetchBatchSize doesn't seem to work properly

I ask a few questions on this topic but still can't get it to work. I have a core data with 10k+ rows of people names that i am showing in a tableview. I would like to be able to search and update the table with every letter. It's very laggy. As suggested i watch the WWWDC '10 core data presentation and was trying to implement
[request setFetchBatchSize:50];
Doesn't seem to work. When i use instruments to check core data it still shows that there is still 10k request when loading the tableview and when i search it also gets all the results.
Is there anything else that needs to be done to set the batch size or thats not something that will help me.
The only thing that seems to work is setting the fetchlimit to 100 when i search. Do you think its a good solution?
Thanks in advance!
The batch size just tells it how many objects to fetch at a time. This is probably not going to help you very much. Let's consider your use case a bit...
The user types "F" and you tell the database, "Go find all the names that start with 'F'" and the database looks at all 10k+ records to find the ones that start with 'F'
Then, the user types 'r', so you tell the database to go find all the records that start with "Fr" and it again looks at all 10k+ records to find the ones that start with "Fr."
All fetchBatchSize is doing is telling it "Hey, when you fault in a record, bring in 50 at once because I'm going to probably need all those anyway." That does nothing to limit your search.
However, setting fetchLimit to 100 helps some because the database starts hunting through all 10k+ records, but once it has its 100 records, it does not have to keep looking at the rest of the records because it already has filled its request. It's done, and stops searching as soon as it gets 100 records that satisfy the request.
So, there are several things you can do, all depending on your other use cases.
The easiest thing to try is adding an index on the field that you are searching. You can set that in the Xcode model editor (section that says Indexes, right under where you can name the entity in the inspector). This will allow the database to setup a special index on that field, and searching will be much faster.
Second, after your initial request, you already have an array of names that begin with 'F' so there is no need to go back to the database to ask for names that begin with 'Fr' If it begins with 'Fr' it also begins with 'F' and you already have NSManagedObject pointers for all of those. Now, you can just search the array you got back.
Even better, if you gave it a sort descriptor, the array is sorted. Thus, you can do a simple binary search on the array. Or, if you prefer, you can just use the same predicate, and apply it to the results array instead of the database.
Even if you don't use the results-pruning I just discussed, I think indexing the attribute will belt dramatically.
EDIT
Maybe you should run instruments to see how much time you are spending where. Also, a badly formed predicate can bring any index scheme to it knees. Code would help.
Finally, consider how many elements you are bringing into memory. CoreData does not fault all the information in, but it does create shells for everything in the array.
If you give it a sort predicate,
I don't know how SQLLite implements its search on an index, but a B-Tree has complexity logBN so even on 30k records, that's not a lot of searching. Unless you have another problem, the indexing should have given you a pretty big improvement.
Once you have the index, you should not be examining all records. However, you still may have a very large set of data. Try fetchBatchSize on those, because it will limit the number of records fetched, and create proxies for the rest.
You can also call countFetchRequext instead of executeFetchRequest to get the number of items. Then, you can use fetchLimit to restrict the number you get.
As far as working all this with a fetched results controller... well, that guy has to know the records, so it still has to do the search.
Also, one place to look... are you doing sections? If you have a user defined comparator for anything (like translating for sections) this will get called for every single record.
Thus, I guess my big suggestion, after making the index change, is to run instruments and really study it to determine where you are spending your time. It should be pretty obvious. That will help steer you toward the real issue.
My bet is that you are still access all of the elements for some reason...

Store and Retrieve auto-fill text terms, iOS

I have a list of about 10,000 phrases (1-5 words each). When the user starts to type in the searchbar, I want to display a tableview that filters through these phrases to find matches. ie: it will function like auto-fill in your browser.
My question is: What is the best way to store this data? Should I just put it in an array that gets initialized when the user searches? Or should it be stored in an external file?
(I am working with iOS).
Thanks!
You could easily do it with an array, but the performance would be very poor.
It would be best to have it in a SQLite (or Core Data) database and search that.
I think having it in a file could be even worse performance than the array.
Save it in a SQLite or Core Data database. You could also use a .plist file, although that might take longer to read through.

global variables, arrays, and search results

I am trying to write an app that searches a website, and takes all of the results and puts them into a customized table. I am an Objective-C and iPhone SDK noob, and am hoping that this logic is what I am trying to accomplish:
1) Searching multiple search engines and pulling all of the data off of each website, storing each into a different array (for example: Searching Google, Yahoo, and Bing for "Shoes", and taking all of the different search results, hyperlinks and all, and storing them into three different arrays)
2) Pulling the data out of each array, and putting into a table (Table view in Interface Builder)
I am assuming that I need to declare global variables, so that they can be called from different classes......right?
What's the syntax for doing this?
How do I set this up in IB?
Did I bite off more than I can chew for this first app?
Thanks for your help!
Aaron, I also think you're biting off more than you can chew WRT a single question on SO, but let me point you to a resource I wrote on a similar topic about how to structure your program.
As an Obj-C noob, you're going to need to take extra care to remember the Model-View-Controller pattern. Extracting data from a web site is a bit of work - and you want to keep that very separate from your display and control code.
Have a clean API model that extracts and sorts data, and have a clear view controller class that reads data from the API.
My advice is to write the whole app in psuedo-code first and try out your thinking on us.

Staggering sqlite records with Objective C

An iphone app we are producing will potentially have a table with 100,000+ records (scaling wise) and I am concerned that loading all this data via a SELECT * command into an array, or an Object will either make the app very slow; or will leave me with memory issues later on.
Obviously loading 100,000+ records into an array when the viewscreen/viewport only shows 30 odd records in a go is a tad silly.
In addition, I am not sure if storing all this data in an object is the right thing to do either.
So my question is, is it possible to stagger sqlite through records, say 50 records in cache and then when you swipe down or up it loads an appropriate amount into the cache. I guess its similar to the JQuery Lazy Loading library where it only loads a little bit on the view port and then loads more as you move down.
I'm looking at JSON, but it appears to only be for Web services as it requires a URL and I am not sure if it works for files that are on the phone.
Therefore. Is there a proper way to load sqlite data into Objective C arrays/objects without causing problems when the data suddenly starts to scale?
Thanks for your help.
You definitely want to avoid loading in everything at once. Instead, you want to use a cursor and smarter queries so that you only pull data out of the database as you actually need it for display; that link points to some hints on how to do that.
Generally, you also want to avoid blindly selecting all columns. This is because you may sometime update the schema to add a column that your existing code would not always know how to extract; far better to name the explicitly columns that you expect and desire.