Saturday, 17 October 2009

MonoTouch for Monospace

MonospaceMonospace is coming up fast, with a whole day's worth of MonoTouch sessions. With that in mind, it seems kinda obvious to make the Monospace schedule available as a MonoTouch app...

Here are some screenshots:



In short, it provides:
  • Conference schedule (day/session/detail views)
  • Speakers (list/detail)
  • Access to the monospaceconf blog
  • Access to @monospace_conf's stream on Twitter
  • A map of the conference location
Some of the fun MonoTouch things I learned along the way include:
  • Creating a UITabBarController in code (no IB)
  • Making icons for UITabBarItem (hint)
  • Creating an 'image watermark' with UIImage behind a UITableView (thanks Mike)
  • Using Linq for Xml to parse Atom feeds (like RSS)
  • Implementing the latest SQLite wrapper from Frank
  • Changing the default UITableViewCell layout in code (eg mutiple lines)
  • Creating a custom UITableViewCell with LoadNib (thanks Simon)
I hope to write some more detail on each of these items... but for now you can download and run the code for yourself:

Monospace2.zip (94Kb)

UPDATE 19-Oct: newer version available
Monospace21.zip (183Kb)

UPDATE 21-Oct: even newer version available
Monospace22.zip (188Kb)

and here's an annotated class diagram/placemat to help make sense of it all:


WARNING: there are plenty of shortcomings/hacks/missing features including: weird lines on the Speaker UITableView, no reloading of data from Blogger or Twitter without restarting, heaps of weird "pointer being freed was not allocated" errors accompanying the SQLite code (only visible in the Application Output window) and probably a pile of bugs I'm not aware of.
USE AT YOUR OWN RISK!

17 comments:

  1. Hey Craig,

    To get rid of the lines being added on the speakers page and the blog page, you'll need those pages inherit UIViewController and not UITableViewController since you're manually creating the TableView itself.

    Cheers,

    ChrisNTR

    ReplyDelete
  2. Could you post the binary so we can side-load it using Installous? :)

    ReplyDelete
  3. @ChrisNTR - d'oh! I stared for ages at that code looking for something like that (I thought maybe I'd call AddSubview twice or something)... it was getting late so I just left it broken. THANKS

    @Jamie - interesting question that I hadn't thought of. In principle I don't have an issue with that (I am all for Open Source and choice), but I need to check I'm not violating any agreements I need to honor... I think my Apple developer certificate conditions require distribution through the AppStore (I don't have an Enterprise account).

    ReplyDelete
  4. You can certainly make the binaries available for your Beta testers:
    http://furbo.org/2008/08/06/beta-testing-on-iphone-20/

    It would be a shame if you didn't own the binaries for your own app!

    ReplyDelete
  5. Thanks Jamie - having a list of defined device ids and provisioning for a limited set (max 100) of beta users is slightly different to making the app available for jailbroken devices.

    I'm just saying I'm not sure whether the agreement I committed to with Apple allows that kind of distribution.

    >>It would be a shame if you didn't own the binaries for your own app!
    Yeah, but it's not as though I got into dev'ing for the iPhone thinking it was a totally open ecosystem...

    ReplyDelete
  6. Craig, the class diagram image is EXTREMELY helpful! As a beginner trying to understand how to structure an application this make a lot more sense then trying to sift trhough code or xib files. Can you post more of theses or have you seen any others like it?

    Thanks,
    Johnny

    ReplyDelete
  7. Hi Craig, thanks for contributing this.

    MonoSpace22 crashes for me without getting anywhere though - stack trace below. Any ideas?

    Thanks.


    at (wrapper managed-to-native) System.Reflection.MonoMethod.InternalInvoke (object,object[],System.Exception&)
    at (wrapper managed-to-native) System.Reflection.MonoMethod.InternalInvoke (object,object[],System.Exception&)
    at System.Reflection.MonoMethod.Invoke (object,System.Reflection.BindingFlags,System.Reflection.Binder,object[],System.Globalization.CultureInfo)
    at System.Reflection.MonoProperty.SetValue (object,object,System.Reflection.BindingFlags,System.Reflection.Binder,object[],System.Globalization.CultureInfo)
    at System.Reflection.PropertyInfo.SetValue (object,object,object[])
    at SQLite.SQLiteCommand/.MoveNext ()
    at System.Collections.Generic.List`1)
    at System.Collections.Generic.List`1
    at System.Linq.Enumerable.ToList
    at Monospace2.SpeakersViewController.ViewDidLoad ()
    at (wrapper runtime-invoke) object.runtime_invoke_void__this__ (object,intptr,intptr,intptr)
    at (wrapper managed-to-native) MonoTouch.ObjCRuntime.Messaging.IntPtr_objc_msgSendSuper (intptr,intptr)
    at (wrapper managed-to-native) MonoTouch.ObjCRuntime.Messaging.IntPtr_objc_msgSendSuper (intptr,intptr)
    at MonoTouch.UIKit.UIViewController.get_View ()
    at Monospace2.TabBarController.ViewDidLoad ()
    at (wrapper runtime-invoke) object.runtime_invoke_void__this__ (object,intptr,intptr,intptr)
    at (wrapper managed-to-native) MonoTouch.ObjCRuntime.Messaging.IntPtr_objc_msgSendSuper (intptr,intptr)
    at (wrapper managed-to-native) MonoTouch.ObjCRuntime.Messaging.IntPtr_objc_msgSendSuper (intptr,intptr)
    at MonoTouch.UIKit.UITabBarController..ctor ()
    at Monospace2.TabBarController..ctor ()
    at Monospace2.AppDelegate.FinishedLaunching (MonoTouch.UIKit.UIApplication,MonoTouch.Foundation.NSDictionary)
    at (wrapper runtime-invoke)
    at (wrapper managed-to-native) MonoTouch.UIKit.UIApplication.UIApplicationMain (int,string[],intptr,intptr)
    at (wrapper managed-to-native) MonoTouch.UIKit.UIApplication.UIApplicationMain (int,string[],intptr,intptr)
    at MonoTouch.UIKit.UIApplication.Main (string[],string,string)
    at Monospace2.Application.Main (string[])
    at (wrapper runtime-invoke)

    ReplyDelete
  8. Nik - it works for me (obviously) on simulator & device with OS3.1.2; I run Snow Leopard and MonoTouch 1.1 for development

    Perhaps you could share your environment details - always helpful in support requests.

    I can see from the stack trace that it appears to be a problem in SpeakersViewController.ViewDidLoad - so perhaps you could comment out that view from being created and added to the TabBarController to see if that helps.

    Also, I see SQLiteCommand.MoveNext mentioned in there, so it's worth checking the .db file is valid SQLite (download one of the free viewer tools to confirm). I presume the project file has preserved the 'build action:content' attribute for the .db file?

    As well as removing it, I would also try commenting out the code in SpeakersViewController.ViewDidLoad and see if that works (might need to comment out other parts of the class too). If it does, gradually add code back in until you find what fails.

    That's all I can think of based on the stack trace you've provided.

    ReplyDelete
  9. Hi Craig, thanks very much for the quick reply.

    Enviro is OSX 10.5.7, Simulator OS 3.1.2, Monotouch 1.1

    The db file and build action are correct yes.

    After a bit of fiddling, it turns out it was all down to the CreateTable<Session>() line in Database.cs - commenting that out, everything runs great. Doesn't seem to be needed?

    Cheers.

    ReplyDelete
  10. Glad it works for you now - the CreateTable<Session>() call was in there from when I first added the SQLite code (it creates the table if it doesn't exist).

    Later I added tables and data directly to the '.db' file using an external tool, making that line redundant.

    I hadn't really planned to update the code again - but if I do I will incorporate this change in case it affects others.

    Thanks

    ReplyDelete
  11. Thank you very much for sharing this nice piece of code!! working with code only (except table cell layout) makes really much more sense than mixing with interface builder. great structure and compact style! just like it has to be.

    i can recommend downloading and learning from this source to everyone who has knowledge in c# and is new to MonoTouch. Many many basic topics are covered here.

    thanks,
    filip

    ReplyDelete
  12. basic == essential here :)

    ReplyDelete
  13. How do you connect to a remote SQL Server to pull data into your application? (i.e. get the data from a corporate server instead of SQLite)

    ReplyDelete
  14. hi Craig, thnx for sharing this. Really helped me in learning.
    however, monospace crashes for me. here is the o/p.

    1. first it errors out while building.
    Monospace22/Monospace2/MapViewController.cs(22,22): Error CS0534: `Monospace2.ConferenceAnnotation' does not implement inherited abstract member `MonoTouch.MapKit.MKAnnotation.Coordinate.set' (CS0534) (Monospace2)

    so i have commented this part and the related part of the code, and got the app build successful. on running in simulator i get the first screen showing the monospace image and there is fails with following error.

    =================================================================
    Got a SIGABRT while executing native code. This usually indicates
    a fatal error in the mono runtime or one of the native libraries
    used by your application.
    ============================================

    am running this with following settings.
    sdk ver 4.1, minimum os version 4.1.
    tried changing various settings but it doesn't work.

    ReplyDelete
  15. Hey Niraj, I haven't upgraded that sample - but Monotouch has changed a bit since it was created. The MKAnnotation.Coordinate binding was changed to require _both_ get/set - but I'm not sure OTTOMH what else has changed to cause the error.
    I will try to load it up in the next few days - I will most likely upload the changes direct to https://github.com/conceptdev/Monospace09

    ReplyDelete
  16. I keep getting this error when I try to run the project thru the iPhone simulator. Tried commenting code, but that goes far and wide... Has anyone found a solution for this issue...
    Note I have fixed the MKAnnotation.Coordinate build error requiring both get and set. I have also commented the CreateTable() call... Any help would be greatly appreciated...


    Error connecting stdout and stderr (127.0.0.1:10001)
    Monospace2(2234,0xa0854540) malloc: *** error for object 0x82625f0: pointer being freed was not allocated
    *** set a breakpoint in malloc_error_break to debug
    Stacktrace:

    at (wrapper managed-to-native) object.__icall_wrapper_mono_marshal_free (intptr)
    at (wrapper managed-to-native) SQLite.SQLite3.ColumnName (intptr,int)
    at SQLite.SQLiteCommand/c__Iterator0`1.MoveNext () [0x00069] in /Users/pradeepkini/Projects/Monospace22/Monospace2/SessionDatabase/SQLite.cs:339
    at System.Collections.Generic.List`1.AddEnumerable (System.Collections.Generic.IEnumerable`1) [0x0001a] in /Developer/MonoTouch/Source/mono/mcs/class/corlib/System.Collections.Generic/List.cs:126
    at System.Collections.Generic.List`1..ctor (System.Collections.Generic.IEnumerable`1) [0x0002f] in /Developer/MonoTouch/Source/mono/mcs/class/corlib/System.Collections.Generic/List.cs:63
    at System.Linq.Enumerable.ToList (System.Collections.Generic.IEnumerable`1) [0x00006] in /Developer/MonoTouch/Source/mono/mcs/class/System.Core/System.Linq/Enumerable.cs:2847
    at Monospace2.SpeakersViewController.ViewDidLoad () [0x00011] in /Users/pradeepkini/Projects/Monospace22/Monospace2/SpeakersViewController.cs:39
    at (wrapper runtime-invoke) object.runtime_invoke_void__this__ (object,intptr,intptr,intptr)
    at (wrapper managed-to-native) MonoTouch.ObjCRuntime.Messaging.IntPtr_objc_msgSendSuper (intptr,intptr)
    at MonoTouch.UIKit.UIViewController.get_View () [0x0002b] in /Users/plasma/Source/iphone/monotouch/UIKit/UIViewController.g.cs:371
    at Monospace2.TabBarController.ViewDidLoad () [0x00088] in /Users/pradeepkini/Projects/Monospace22/Monospace2/TabBarController.cs:36
    at (wrapper runtime-invoke) object.runtime_invoke_void__this__ (object,intptr,intptr,intptr)
    at (wrapper managed-to-native) MonoTouch.ObjCRuntime.Messaging.IntPtr_objc_msgSendSuper (intptr,intptr)
    at MonoTouch.UIKit.UITabBarController..ctor () [0x00031] in /Users/plasma/Source/iphone/monotouch/UIKit/UITabBarController.g.cs:63
    at Monospace2.TabBarController..ctor ()
    at Monospace2.AppDelegate.FinishedLaunching (MonoTouch.UIKit.UIApplication,MonoTouch.Foundation.NSDictionary) [0x0000f] in /Users/pradeepkini/Projects/Monospace22/Monospace2/AppDelegate.cs:29
    at (wrapper runtime-invoke) .runtime_invoke_bool__this___object_object (object,intptr,intptr,intptr)
    at (wrapper managed-to-native) MonoTouch.UIKit.UIApplication.UIApplicationMain (int,string[],intptr,intptr)
    at MonoTouch.UIKit.UIApplication.Main (string[],string,string) [0x00038] in /Users/plasma/Source/iphone/monotouch/UIKit/UIApplication.cs:26
    at Monospace2.Application.Main (string[]) [0x00000] in /Users/pradeepkini/Projects/Monospace22/Monospace2/Main.cs:16
    at (wrapper runtime-invoke) .runtime_invoke_void_object (object,intptr,intptr,intptr)


    Debug info from gdb:

    /tmp/mono-gdb-commands.JGb8b3:1: Error in sourced command file:
    unable to debug self

    =================================================================
    Got a SIGABRT while executing native code. This usually indicates
    a fatal error in the mono runtime or one of the native libraries
    used by your application.
    =================================================================

    ReplyDelete

Note: only a member of this blog may post a comment.