Today I have for you two special goodies. I used the entire day today to put the finishing touches on two new components that you find released in version 1.4 of DTFoundation.
On a recent project I was fed up with having to deal with a SQLite database “by hand”. So I wrote a wrapper for it that allows you to interact with the database in convenient Objective-C, as well as perform queries on a background queue.
The second new project is what the general public has come to call a “Hamburger Menu”. This is the kind of side panel menu that you can see in many popular apps.
And Yes, YES, I am aware that there are “finished” open source components out there that provide similar functionality. I like to tinker with these things because I am learning a hell of a lot about how to make great components. In short: for the fun of it.
Version 1.4 Change Log
- ADDED: [DTSidePanel] Container Controller
- ADDED: [DTSQLite] Wrapper class for SQLite3 Databases
- ADDED: [DTAlertView] Method to create a cancel button and/or set a cancelBlock.
- CHANGED: Moved experimental striped layer into Experimental folder
DTSQLiteDatabase
The idea is that I want to have an NSObject represent the database and then have a simple method to query it.
// get the path in a way that also works in unit tests NSString *path = [[NSBundle bundleForClass:[self class]] pathForResource:@"database" ofType:@"sqlite"]; // abort if the path does not exist NSAssert(path, @"No db file found in app bundle"); // store in IVAR _database = [[DTSQLiteDatabase alloc] initWithFileAtPath:path]; |
The to perform a query you can simple call the following:
NSString *sql = @"SELECT * from mytable;"; NSError *error = nil; NSArray *results = [_database fetchRowsForQuery:sql error:&error]; if (!results) { // deal with error } |
The results are automatically repackaged for you into an NSDictionary for each row. Note that in SQLite all column names turn to lowercase. At this moment this supports the SQLite types TEXT, INTEGER and FLOAT. If you need more let me know, those are easy to add.
If you are the only person making calls to fetchRowsForQuery:error: and you don’t care that this is executed on the current (main) thread, then that’s all it takes.
You get thread safety and the ability to synchronize fetches onto a private background queue via performBlock: and performBlockAndWait: just like you are used to from Core Data managed object contexts that have the private queue concurrency type:
[_database performBlock:^{ // this code occurs in background NSError *error = nil; NSArray *results = [_database fetchRowsForQuery:sql error:&error]; // do something with the results }]; |
DTSQLiteDatabase has a features that famous FMDB does not have, but which I needed. Imagine you starting a query that might take a while in the background, but while it is underway the user decides that he doesn’t want to wait. You can interrupt long-running queries via the cancelAllQueries method.
I only implemented the absolutely necessary parts, but this works very nicely so far for my use case. The documentation can be found on our docs server.
The “Hamburger Menu”
There is a long list of apps that use said UI paradigm. The idea is that you are not waisting screen real estate by having tabs at the bottom of your screen like you would with a UITabBarController. Or a big viewController tree under a UINavigationController.
Instead you have side panels. Often on the left side, sometimes also on the right. And you would reveal these side panels either by swiping sideways or by the famous “Hamburger Button”. I long wondered why it is called that … Look at this screen shot, with a little imagination you can see two parts of the hamburger bun with a piece of meat in between. (Thank you René Pirringer for drawing the button for my demo app)
For a short while I considered calling this DTHamburgerMenuController, for the fun of it. But eventually I decided on DTSidePanelController instead, sounds more professional.
It has these features:
- Support fixed or variable sized side panels. A fixed panel always keeps its width on rotation. A variable-width panel resizes such that you always have sufficient place to tap the center panel for closing.
- Supports embedding UINavigationControllers
- Swiping needs to be a minimum distance to be registered to avoid problems with other horizontal gestures
- Tap-to-close an open side panel
- Rotation support, panel view controllers are queried for supported orientations, compatibly with iOS 5 and above.
- Beautiful code and nice documentation
- Appearance notifications for the view controllers and views fully implemented. viewWillAppear fires as soon as the panel becomes visible.
- Support for accessing the side panel controller via property, self.sidePanelController from anywhere inside the view controller hierarchy
- Fast shadow with shadow path
- Ability to prevent closing/moving the center panel via delegate method. For example if you have something modal going on that you want the user to finish first
There are a few things that I decided against doing for the first version. For instance some implementations have a rubberbanding effect following the animation. The problem with this approach is that to support that you would have to under-lap the panels under the center panel so that you don’t see the background when it overshoots the limit. It is probably for this reason that most professionally made apps don’t have that. YouTube does rubberband, Facebook doesn’t.
The demo also shows how to lock a panel. If you go to the right panel you get a switch to prevent closing of the panel.
Conclusion
You are welcome to give my components a try, even if they are not as popular as FMDB or the various other implementations of the “hamburger menu”. I am interested to receive your comments or feedback.
Categories: Updates
Very nice work!
Btw, it looks like a Hamburger because you get it with a Side Menu 😉