Introducing MonoTouch.SQLite
I've been working on a personal side-project writing an app for the iPad that makes use of SQLite-Net, displaying that data in a UITableView.
Up until this past week, I had been using Miguel de Icaza's wonderful MonoTouch.Dialog library for displaying my data. Unfortunately, I wanted search filtering to be persistent, which means that I really needed to use Apple's UISearchDisplayController but I couldn't find an easy way to retrofit that onto MonoTouch.Dialog's DialogViewController to replace the simpler UISearchBar API that it currently uses. Since I had to look at creating an alternate solution, I figured I might as well solve the other potential problem I had with MonoTouch.Dialog, which is that my app really needed to be able to handle tables with a massive number of items. This brings us to...
MonoTouch.SQLite
MonoTouch.Dialog really made using UITableViews in iPhone and iPad apps trivial and I wanted to try and repeat at least some of that with MonoTouch.SQLite.
The first thing I had to do was to figure out a way of modeling the data in such a way as to allow a generic class to do most of the work for the developer. After a few sleepless nights of hacking last weekend, I figured out a fairly simple approach that seems to work pretty well. I started off thinking that I wouldn't be able to get around having to have a subclassable model, so I made most everything virtual. This is the public API that I came up with:
public class SQLiteTableModel<T> : IDisposable where T : new ()
{
public SQLiteTableModel (SQLiteConnection sqlitedb, int pageSize, SQLiteOrderBy orderBy, string sectionExpr);
// 2 ways of setting the search criteria
public SQLiteWhereExpression SearchExpression { get; set; }
public string SearchText { get; set; }
// Gets the total number of table rows
public int Count { get; }
// Gets the number of table sections
public int SectionCount { get; }
// Gets the section titles
public string[] SectionTitles { get; }
// Gets the row count for a particular section
public int GetRowCount (int section);
// Get the index of an item
public int IndexOf (T item, IComparer<t> comparer);
// Convert item index into a section and row
public bool IndexToSectionAndRow (int index, out int section, out int row);
// Convert section and row into an item index
public int SectionAndRowToIndex (int section, int row);
// 2 ways of getting an item
public T GetItem (int section, int row);
public T GetItem (int index);
// Reset the state of the model
public void ReloadData ();
}
You can see the full class implementation here.
It turns out, though, that it really isn't necessary to subclass my model unless you want to have finer control over the specific SQL query commands that it makes (all of those methods are virtual).
SQLiteTableViewController<T>
As I started porting my iPad app to use my SQLiteTableModel class, I started to realize that I could abstract a lot of my usage of the model into a reusable base class. What I came up with will blow your mind.
Are you ready?
In order to populate a UITableView with the contents of an SQLite table, all you have to do is subclass SQLiteTableViewController<T> and implement 1 method:
protected UITableViewCell GetCell (UITableView tableView, NSIndexPath path, T item)
That's it.
I've written up a sample iPhone app that illustrates just how easy this is.
But wait! There's more!
If you order in the next 30 minutes, you can also get this free complimentary Sham-Wow!
Okay, just kidding about that Sham-Wow! bit, but I wasn't kidding about there being more:
Remember when I said one of the problems I wanted to solve was persistent search filtering? Yea, well, I did it. SQLiteTableViewController handles all of that for you as well. In fact, give searching a try in that sample above.
At this point I bet you're thinking, "wow, how could this get any better?"
I'll tell you. Remember how SQLiteTableModel had 2 methods for setting the search criteria? Well, the one that takes a string parses it to create a SQLiteWhereExpression allowing the user to match against specific fields. For example, if you had the following data item:
public class Contact {
public string FirstName;
public string LastName;
public string PhoneNumber;
public string Address;
public string Comments;
}
...the user could type:
address:"Newton, MA"
and SQLiteTableModel would construct a query to match "Newton, MA" against only the Address field.
If the user, instead, types:
address:"Newton, MA" firstname:Jane
then the matches that would display in the list would be limited to contacts with a first name of "Jane" who live also in "Newton, MA".
I've also taken the liberty of implementing a SQLiteSearchAliasAttribute that allows you to specify aliases for your fields (or even the same alias to multiple fields!). For example, you could do this:
public class Contact {
[SQLiteSearchAlias ("first")][SQLiteSearchAlias ("name")]
public string FirstName;
[SQLiteSearchAlias ("last")][SQLiteSearchAlias ("name")]
public string LastName;
[SQLiteSearchAlias ("phone")]
public string PhoneNumber;
public string Address;
public string Comments;
}
This would allow your users to use "name" to match against either FirstName or LastName!
It also means they can type "first" instead of "firstname" to match against only the first name, as in the above example.Where Can I Find This Awesome Library?
Glad you asked! You can find it on my GitHub page: MonoTouch.SQLite.
Well? What are you waiting for? Get hacking!
On the road...
Busy times currently as we’re heading to releases of ownCloud. The syncing client I am working on plays a role for that and thus I was doing a lot of work on csync upstream and mirall to get that going. Meanwhile I succeeded to get mirall running under Win32, it was quite an experience for me digging through the mud of various compilers and environments and the different understandings of C standards, especially since csync is plain C and never run on Win32 before.
Last week I have been on CeBIT for a day, which is a huge and busy event. We had a nice preview running there with syncing between the web client and the desktop clients on Windows and Linux, as well as on an Android device. That already worked quite ok, nevertheless I got quite some bug reports since then. And I still have to work with csync upstream to get patches in there before we’re ready for a public beta.
This weekend I will be at the Chemnitzer Linuxtage together with friends from the openSUSE project. I will show some ownCloud syncing there as well, so if you like show up at the openSUSE booth for a demo and a chat :-)
php5.3 packages in SLES 11 SP2
SLES 11 SP2 ships php5.3 binaries but the default package php5 still installs php5.2 which already has reached upstream end of life and should be considered unsupported by any means. Recent versions of phpunit and other developer tools won’t provide all features on php5.2 any more.
You must use apache2-mod_php53, php53, php53-mysql and so on if you want to use php on SLES.
ESR and Thunderbird under KDE
A quick update about recent changes in Mozilla applications for openSUSE.
With the release of Firefox and Thunderbird 11 (and Seamonkey 2.8) the older versions (10) got obsolete as always. But Mozilla created ESR (Extended Support Release) for Firefox and Thunderbird based on versions 10 and will maintain them for a longer time. Please read the FAQ about the details. For openSUSE we will not switch to these versions for different reasons but I’ll provide these from the buildservice repository mozilla. You should be able to install the current versions (10.0.3) of Firefox and Thunderbird by choosing firefox-esr or thunderbird-esr (there is also xulrunner-esr) in your package manager if you added that repository before. Please note that this is opt-in only and it’s not possible to install latest normal version and ESR versions in parallel. They are using the same profile directory and therefore I didn’t give them a separate installation directory neither. It’s also a bit risky to jump between ESR and normal versions because of the profile. So as normal version gets higher every six weeks the riskier to jump back and forth. Basically those ESR versions should probably be used only if really necessary but I still wanted to provide that possibility. If you install the ESR versions and found issues please let me know. Because of the renaming and parallel usage of the branding packages I might have missed some packaging foo to make updates in every case smooth.
A similar topic is about Firefox 3.6 and Thunderbird 3.1. The latest round of updates (3.6.28 / 3.1.20) was most likely the last one and people should start switching to more recent versions. That also means that 11.4 will get Thunderbird 12 as replacement for 3.1.20 with the next round. Other versions are already on the latest packages. (Evergreen will likely switch to the ESR versions btw.)
And about the last announcement (from my “quick update”) people might notice that Thunderbird 11 now got at least some of the KDE integration from Firefox as people kept pinging me about it. (And Firefox’ KDE integration is also back for the official updates!)
subversion with libserf – continued
Further about my work on packages for Apache Subversion with support for serf / libserf / ra_serf, that repository access module was not made default in the 1.7 release after all. Anyway, version 1.0.13 of serf is now available in devel:libraries:c_c++ with the intention of getting this into and in Factory. You will find current Apache Subversion packages with fixed conditional compilation against serf in home:AndreasStieger:serf home:AndreasStieger:branches:devel:tools:scm:svn devel:tools:scm:svn for testing.
Updated 27/05/2012: repository locations
And again after SR#122507 was accepted.
postifx в SuSEconfig
В openSUSE 12.1 postfix был откручен(750685) от SuSEconfig, поэтому запускать тот самый волшебный скрипт теперь надо так:
MD5DIR=/var/adm/SuSEconfig/md5 /usr/sbin/SuSEconfig.postfix
Все остальное работает как раньше: /etc/sysconfig/postfix, /etc/sysconfig/mail остаются в силе. Базы алиасов пересобираются сами при rcpostfix restart.
Установка openSUSE 12.1 c флешки
Недавно попробовал установить новую версию моего любимого дистрибютива с флешки.
Так как свободной флешки больше 4 гигабайт в наличии не оказалось, установку делал с образа LiveKDE 12.1 — с планами доустановить необходимый софт позже через интернет.
В версии 11.4 весь необходимый софт ( openSUSe studio и все прилагающиеся необходимые пакеты) были установлены, запись дистрибютива на флешку прошел без сучка и задоринки. И сама установка прошла как по маслу, тем более что с флешки установка идёт быстрее, чем с СД или ДВД. Установил, настроил, добавил необходимые русификационные пакеты — и вот, всё работает, все замечательно. Новая версия пока у меня нареканий не вызвала, правда, в ней я работаю не часто
Meeting the Incas in memory of Jane Morffew
C++ vector iterators, why over-use?
I understand that it can be seen as nice and orthogonal that all kinds of containers have a uniform paradigm to access them sequentially. Or something similarly sublime.
But in the specific case of vectors, in a method of a class that has a vector as a private field (and said method thus knows that it is implemented as a vector), what does one win by accessing the vector through iterators and not indexing?
I mean, using indexing is much safer.
Case in point:
Klass::Method()
{
VectorMemberType::iterator it = vectorMember::begin();
while (it != vectorMember::end()) {
VectorElement el = *it;
if (SomeTest(el))
DoSomethingToTheVectorThatMightPushBack();
++it;
}
}
Now, as it happens increasing a vector size (for instance by push_back()) does not always make iterators open on it de facto invalid with GCC, it seems, the code just silently does something slightly wrong or whatever. Apparently it does make the iterator really invalid much more easily with MSVC, leading to a crash.
Working around that while still using iterators gets pretty ugly, doesn't it? You have to restart the iteration and skip the number of elements already handled. Or change the code structure completely.
Compare to simply using indexing:
Klass::Method()
{
size_t it = 0;
while (it < vectorMember::size()) {
VectorElement el = vectorMember[it];
if (SomeTest(el))
DoSomethingToTheVectorThatMightPushBack();
++it;
}
}
No stateful iterator that might get invalidated when the vector is resized. Just a simple integer index. What is so wrong and ugly with this? That it, shock horror, looks more like C?
Ανοικτός κώδικας και στο GDC 2012
Αυτή την εβδομάδα διεξάγεται το Συνέδριο Προγραμματιστών Παιχνιδιών, Games Developer Conference, στο Moscone Center, στο Σαν Φρανσίσκο. Η RIM είναι χορηγός, καθώς και κατέχει ένα περίπτερο στην Expo και έχει αρκετές συνεδρίες.
Τα ανοικτού κώδικα project μας(όπως ακριβώς αναφέρει ο pelegri)αποτελούν βασικό τμήμα των συνεδριών. Μερικά από τα repos που θα αντικρίσετε στις συνεδρίες του RIM στο GCD περιλαμβάνουν τα ακόλουθα:
- Gameplay – το δικό μας ανεξάρτητο πλατφόρμας 3D native framework παιχνιδιών
- NDK-Δείγματα – δείχνει τις δυνατότητες της πλατφόρμας Native PlayBook, συμπεριλαμβανομένων των κοινωνικών παιχνιδιών που χρησιμοποιούν BBM και Scoreloop.
- Όλα τα HTML5 repos, συμπεριλαμβανομένων WebGL-Δείγματα (w/ TunnelTilt), WebWorks, WebWorks-TabletOS, WebWorks-Δείγματα, WebWorks-Community-APIs, Ripple, AliceJS, bbUI.js.
- Κοινωνικά παιχνίδια σε WebWorks και σε BlackBerry Smartphones
- Το καταπληκτικό μας Webkit-based πρόγραμμα περιήγησής μας (τόσο για PlayBook και για τα πιο σύγχρονα BlackBerry smartphones)
- και άλλα …
Είναι ένα ενδιαφέρον συνέδριο για τους παιχνιδάδες και κυρίως για αυτούς που πειραματίζονται με τον προγραμματισμό παιχνιδιών. Επίσης, μία “ξενάγηση” σε όλα τα παραπάνω θα ήταν μία υπέροχη, διασκεδαστική και εκπαιδευτική hμέρα… Ελπίζω όποιος παρευρεθεί να απολαύσει όλες τις συνεδρίες.
Δείτε περισσότερες λεπτομέρειες, συμπεριλαμβανομένου του πλήρους καταλόγου των συνεδριών.
Πληροφορίες αντλήθηκαν από άρθρο της ιστοσελίδας openbbnews.wordpress.com