Berichten met label iPhone

How to import contacts from iPhone to a built-in navigation in your car

There are a lot of questions on the Internet concerning how to export contacts from iPhone into a car’s navigation. In particular, I know that many Toyota owners experience this problem. For example, pairing iPhone with my Toyota Auris Executive went well, but when I tied to transfer contacts into the navigation system, I just got a notification that Bluetooth device is not connected.

My car has a build-in navigation system with a car kit, as well as a Bluetooth connection.  I also found information on how to export contacts in the instruction given. But this is not the case for iPhone users, due to the difference in Bluetooth connection systems: the navigation expects pushing of contacts, however iPhone doesn’t send contacts automatically.

Of course, you can always add contacts manually to your navigation system, spending maybe a few hours on that. And you can use another phone, which supports your car’s Bluetooth. For that just copy all your contacts to that other phone or insert your sim there using a micro-sim adapter.

But what to do when you don’t have another phone or micro-sim adapter? Or when you can’t copy your contacts? Or when you don’t have time to add them all manually?

I found my way, which you may found useful: it is exporting contacts from a laptop. In this example I used MacBook Pro with installed MacOS Lion, however I believe it’s also possible to use a laptop running Windows (then you just need to find out where your contacts from iPhone are stored).

With this 10 steps’ guideline you will have all your contacts transferred to the car:

1. Sync your iPhone with your MacBook (see iTunes tutorials).  Skip this step if already you use your iPhone with that MacBook.

2. Open Address Book (Application->Address Book). If everything is done correctly, you should see all your iPhone contacts.

3. Select all contacts (cmd+A).

4. Go to File->Export->Export vCard… and save it for example as vCards.vcf.

adress book

5. Now go to your car and pair MacBook with the navigation via Bluetooth.

6. Select in the navigation Telephone->Settings->Transfer data->Select some group.

IMG_0938

IMG_0933

IMG_0934

You will see on the display that contacts are being imported (but be aware at that moment nothing yet happens).

IMG_0936

7. On your MacBook click the Bluetooth icon (on the right -top side of the panel), then select your car’s connection and click Send file.

8. Choose vCards.vcf file, that you have previously created (see step 4), and click Send.

9. When importing is done, you should see a confirmation message on the navigation display. During the importing process you can see the progress on the MacBook.

10. Now you can disconnect your MacBook from the navigation.

I hope this tutorial has saved you a few hours of manually adding contacts.

, , , , , , , , ,

3 reacties

Getting to know CouchDB – 2/x

Last time around, we were able to store the OSGi log messages into a CouchDB. Now I want to tap into the _changes API that CouchDB offers. The options are simple, connect to the ‘_changes’ document in a CouchDB database and you will be presented with a log of all changes that have occurred on the database.

http://localhost:5984/db/_changes

{"results":[
{"seq":3,"id":"_design/app","changes":[{"rev":"2-0dc1002d841221e8d8d7f325b87ffd67"}]},
{"seq":196,"id":"994cf6817a74882cecda6425e8001a96","changes":[{"rev":"193-083ec5c1e1359789eb2cf09c46097fee"}]}
,
"last_seq":196}

For each document in the database only the last change is presented. This could result in quite a lot of information. It is therefore also possible to fetch changes while applying a server-side filter. For this to work, you first need to define a filter in a design document. Mine looks like this:

function(doc, req) {
    if (doc.type == "EVENT") { return true; }
    return false;
}

and is stored (using couchapp) in a design document called ‘app’. The name of the filter is ‘events’. The filters’ meaning should obvious: pass through all documents for which the function returns ‘true’. The proper URL for accessing the changes will now be:

http://localhost:5984/db/_changes?filter=app/events

{"results":[
{"seq":196,"id":"994cf6817a74882cecda6425e8001a96","changes":[{"rev":"193-083ec5c1e1359789eb2cf09c46097fee"}]}
],
"last_seq":196}

The “last_seq” part can be used for bookkeeping: If you plan to make  multiple calls to the _changes feed (say every hour) then it is nice to be able to skip the ones you already saw during a previous call. So, the second time you call the _changes feed, you can skip all previous changes by employing the following URL:

http://localhost:5984/db/_changes?filter=app/events&since=196

{"results":[

],
"last_seq":196}

Obviously, no update has occurred since we accessed the _changes feed for the first time. If, however we now add a new document to the database (with doc.type == “EVENT”) and call the _changes feed again:

http://localhost:5984/db/_changes?filter=app/events&since=196

{"results":[
{"seq":197,"id":"f0a4a559fac65ab3cca87baf1c014fa7","changes":[{"rev":"1-c8dfffec4e08ca8db2b95f30613e213d"}]}
],
"last_seq":197}

Also, a call to “http://localhost:5984/db” will result in a JSON object, where “update_seq” provides the current update sequence. This comes in handy if you’re really not interested in previous changes:

http://localhost:5984/db

{"db_name":"db","doc_count":4,"doc_del_count":0,"update_seq":196,
"purge_seq":0,"compact_running":false,"disk_size":1871961,
"instance_start_time":"1282049630257719","disk_format_version":5,
"committed_update_seq":196}

This is all great functionality if your time granularity is in the order of hours or days. But hardly optimal if you want to be notified immediately of changes to the database. Fortunately, by supplying “feed=continuous” to the URL, CouchDB will keep your socket connection open and supply the changes as soon as they become available. Each change is represented by a well-formatted JSON line. This breaks from the previous examples, where the complete response consisted of well-formatted JSON, so beware!

http://localhost:5984/db/_changes?filter=app/events&since=196&feed=continuous

{"seq":197,"id":"f0a4a559fac65ab3cca87baf1c014fa7","changes":[{"rev":"1-c8dfffec4e08ca8db2b95f30613e213d"}]}
...
...
{"last_seq":197}

Eventually, if no changes have been sent for 60 secs, the socket connection closes. Before it does so, it spits out the last_seq, again for bookkeeping purposes.

I was wondering if it would be possible to create a simple iPhone/iPad application that is able to report specific events on a MapView using the _changes feed from CouchDB. All one then has to do as iPhone/ iPad application is connect to the continuous feed, parse the JSON data and display the events on your MKMapView. Server-side, all one has to do is insert/ update documents in the database. How easy!

So I started off by connecting to the _changes feed using an asynchronous NSURLConnection, expecting that its delegate would receive connection:didReceiveData: calls on each change. Unfortunately, this did not work: The NSURLConnection employs buffering internally that cannot be circumvented. Thus only after about 5 or 6 updates the delegate received some data. This is definitely not good enough. Some searching pointed me to the CFSocket/NSStream class. This class fortunately employs some more basic (read: unbuffered) socket handling, allowing me to receive data from the socket as soon as it becomes available!

    //open the socket
    CFReadStreamRef readStream;
    CFWriteStreamRef writeStream;
    CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)[theURL host], [[theURL port] intValue], &readStream, &writeStream);

    inputStream = (NSInputStream *)readStream;
    outputStream = (NSOutputStream *)writeStream;

    [inputStream setDelegate: self];
    [outputStream setDelegate :self];
    [inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    [outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    [inputStream open];
    [outputStream open];    

The containing class is set as delegate for both the NSInputStream and NSOutputStream. This causes the following method being called, based on events that occur on the streams:

/* stream eventing */
- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode {

    switch(eventCode) {
        case NSStreamEventOpenCompleted:
            [self connection: nil didReceiveResponse: nil];
			break;

		case NSStreamEventErrorOccurred:
            [self connection: nil didFailWithError: [stream streamError]];
			break;

		case NSStreamEventEndEncountered:
            [stream close];
            [stream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
            [stream release];
            inputStream = nil;
            outputStream = nil;
            [self connectionDidFinishLoading: nil];
			break;            

        case NSStreamEventHasSpaceAvailable:
        {
            if (stream == outputStream) {
                [self connection: nil willSendRequest: [NSURLRequest requestWithURL: theURL] redirectResponse: nil];

                NSString *str = [NSString stringWithFormat: @"GET %@?%@ HTTP/1.0\r\n\r\n", [theURL path], [theURL query]];
                const uint8_t *rawstring = (const uint8_t *)[str UTF8String];
                [outputStream write:rawstring maxLength: [str length]];
                [outputStream close];
            }
        }
            break;
		case NSStreamEventHasBytesAvailable:
        {
			if (stream == inputStream)
			{
				uint8_t buffer[1024];
				int len;
				while ([inputStream hasBytesAvailable])
				{
					len = [inputStream read: buffer maxLength: sizeof(buffer)];
					if (len > 0)
					{
						NSData *theData = [[NSData alloc] initWithBytes: buffer length:len];
                        [self connection: nil didReceiveData: theData];
					}
				}
			}
        }
            break;
    }
}

As you can see, this method kind of delegates the occurring events to calls to the NSURLConnectionDelegate (which the containing class also implements, due to my initial effort to read the changes feed using a normal NSURLConnection).

Then, the connection:didReceiveData method handles the actual changes:

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    NSString *str = [[NSString alloc] initWithData:data encoding: NSUTF8StringEncoding];

    NSArray *ary = [str componentsSeparatedByString:@"\n"];
    for (NSString *line in ary) {
        if ([line length] > 0 && [line characterAtIndex: 0] == '{') {
            id json = [line JSONValue];

            NSDictionary *dict = (NSDictionary*)json;
            NSObject *seq = [dict objectForKey: @"seq"];

            if (seq && delegate) {
                [delegate changeReceived: dict];
            }
            NSObject *last_seq = [dict objectForKey: @"last_seq"];
            if (last_seq && delegate) {
                int last = [((NSNumber*)last_seq) intValue];
                [delegate lastSequence: last];
            }
        }
    }

}

This method converts the JSON data to a NSDictionary and forwards these changes to a (self-defined) @protocol called ChangesDelegate:

@protocol ChangesDelegate

@optional

-(void) changeReceived:(NSDictionary*) dict;
-(void) lastSequence:(int) last;
-(void) changesComplete:(NSError*)error;

@end

The implementation that performs the actual calls to CouchDB can be created using:

    m_changes = [[Changes alloc] initWithHost: @"localhost" database: @"db" andFilter: @"app/events"];
    m_changes.delegate = self;

    m_lastSeq = [m_changes last_seq];

Since the calling class also implements the ChangesDelegate @protocol, it will receive the changes events. I am currently using it to display MKAnnotations onto a MKMapView and it works like a charm!

Thank you CouchDB for making life easy!

p.s. I’ve made the Changes class available through github: changesfeed_xcode. Enjoy!

, , ,

Nog geen reacties

PhoneGap, een alternatief voor native mobiele applicaties

PhoneGap, een alternatief voor native mobiele applicaties

PhoneGap is een interessante open source alternatief voor het schrijven van native applicaties voor elk (mobiel) platform dat er is. In het kort komt het erop neer dat PhoneGap zorgt dat je een HTML applicatie met javascript.  De specifiek API, zoals location, contact, e.d. worden afgeschermd door een standaard API van PhoneGap.

iPhone

Voor de iPhone kan de HTML applicatie gewoon worden aangeboden via de appstore. Dit is dan ook direct de truc waardoor er voldoende rechten zijn om de hardware aan te spreken. Er zijn al vele applicatie geplaatst in de appstore (zie een selectie in www.phonegap.com/apps).  Er is tevens een getting started en er zijn  extra plugins beschikbaar

Ondersteunde platformen

Naast iPhone wordt zowel Android, Blackberry, Symbian, Palm, N900 en Windows Mobile. Ook Windows Mobile 7 is zodra dit uitkomt eenvoudig te ondersteunen en ze zullen ook geen blokkade opwerpen in het voordeel van silverlight. Interesante gedachte is natuurlijk ook de iets minder mobiele system met Linux, Windows MacOS hebben ook allemaal een browser.

IPHONE ANDROID BLACKBERRY SYMBIAN PALM
GEO LOCATION
VIBRATION
ACCELEROMETER OS 4.7
SOUND
CONTACT SUPPORT N/A

Voor meer informatie zie www.phonegap.com

, , , , , ,

1 reactie

Building iPhone applications using MonoTouch, part 5: software design considerations

In the previous 4 posts (4, 3, 2, 1) I gave a lot of attention to the overall structure of an iPhone application. In this post I want to talk about a topic that is more concerned with general software design issues: where do I do what?

Get SOLID

There are two things that I always try to keep in mind when making software: loose coupling and tight cohesion. In other words:

  1. make sure your classes don’t know things that they don’t need to know
  2. make sure your classes are good at one thing and one thing only

These guidelines are part of the 5 SOLID principles of class design by Uncle Bob Martin:

  1. Single Responsibility Principle
  2. Open Closed Principle
  3. Liskov Substitution Principle
  4. Interface Segregation Principle
  5. Dependency Inversion Principle

This stuff is really interesting and sort-of scientific, but it is also like making your database comply to the 5-th Normal Form: nobody does that. You’re happy with a 3rd Normal Form database. So I’m happy when I see code that complies with at least two of the above principles.

So what I do when building my iPhone apps is constantly asking myself: should this code be in this place? Sometimes I know right away that the answer is No, but still leave it there until I have a better idea on where to put it then. And with the (for me) rather unusual structure that the Cocao Framework forces upon me, it may take some time before I eventually find out where to put it.

Let me give you an example.

When you want to load data into a UITableView you must create a UITableViewDataSource and assign that to the DataSource property of your UITableViewController. Like this:

public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
	tableView.DataSource = new LeesPlankjeDataSource();
	window.AddSubview (tableView);
	window.MakeKeyAndVisible ();
	return true;
}

The class instantiated at line 3 is something like this:

public class LeesPlankjeDataSource : UITableViewDataSource
{
	private string[] woordjes = new string[] {"aap", "noot", "mies"};
	public override UITableViewCell GetCell (UITableView tableView, MonoTouch.Foundation.NSIndexPath indexPath)
	{
		UITableViewCell cell = tableView.DequeueReusableCell("plankje");
		if (cell == null)
		{
			cell = new UITableViewCell(UITableViewCellStyle.Default, "plankje");
		}
		cell.TextLabel.Text = woordjes[indexPath.Row];
		return cell;
	}
 
	public override int RowsInSection (UITableView tableview, int section)
	{
		return woordjes.Length;
	}
}

On line 3 you see the actual “data store”, and on line 4 an important override. This method gets called by Cocoa when loading data in your UITableView. So the controller has a data source and the appropriate methods get called by the framework.

On to a more realistic implementation

If I want to advance my class a bit, I could imagine that the data is not a fixed array of strings, but gets passed in at construction time. Maybe I read from a file or from a URL.

That changes my class to this:

public class LeesPlankjeDataSource : UITableViewDataSource
{
	private string[] _dataStorage;
 
	public LeesPlankjeDataSource(string[] data)
	{
		_dataStorage = data;
	}
 
	public override UITableViewCell GetCell (UITableView tableView, MonoTouch.Foundation.NSIndexPath indexPath)
	{
		UITableViewCell cell = tableView.DequeueReusableCell("plankje");
		if (cell == null)
		{
			cell = new UITableViewCell(UITableViewCellStyle.Default, "plankje");
		}
		cell.TextLabel.Text = _dataStorage[indexPath.Row];
		return cell;
	}
 
	public override int RowsInSection (UITableView tableview, int section)
	{
		return _dataStorage.Length;
	}
}

And the main.cs gets these lines:

	string[] woordjes = File.ReadAllLines("woordjes.txt");
 
	tableView.DataSource = new LeesPlankjeDataSource(woordjes);

Make sure when you have files that you want to be deployed with your app to set the build-action on the file to “content”:

BuildActionThat’s all neat. The DataSource gets it data from the outside and doesn’t care if it comes from a file or a network-connection.

So now we want some action when the user taps a row. You have no choice but to implement this in a delegate (a UITableViewDelegate of course) and then override the RowSelected() method. This method is called for you by Cocoa and as parameters you get a UITableView that the tapping happened on and the Row number that was tapped:

public class LeesPlankjeViewDelegate : UITableViewDelegate
{
	public override void RowSelected (UITableView tableView, MonoTouch.Foundation.NSIndexPath indexPath)
	{
	}
}

But what can I do in this method? Let’s say I want to do a MessageBox-ish thing to show what word was chosen. All I have is an index to the row in my data source. But I don’t have the data source itself in this class. I need some way to acces my original data store.

I could do somehting like this:

public override void RowSelected (UITableView tableView, MonoTouch.Foundation.NSIndexPath indexPath)
{
	string message = tableView.DataSource.GetCell(tableView,  indexPath).TextLabel.Text;
	using (var alert = new UIAlertView ("", message, null, "OK", null))
	{
		alert.Show ();
	}
}

So I ask the TableView for its data source, then ask the data source to give me the cell that is on the given index, and then ask the cell for the text of the label. It works, but it is butt-ugly. Why? Because now the delegate knows about the data source too. And I think it shouldn’t, because all the delegate needs to do is handle UI-interactions from the user. It should say “Hey, someone tapped me on this row, do something with it” and then leave the actual work to someone else.

I think it would be reasonable to leave the work to the controller. For me, a controller is always the man-in-the-middle, doing the real work brokering between the model and the view. But if I choose that, I have to pass in the controller when constructing the Delegate, like this:

tableView.Delegate = new LeesPlankjeViewDelegate(tableViewController);

And since the tableViewController is only known so far in the Interface Builder, I have to make the controller available in my code by creating an outlet. Sigh…. even more code in my FinishedLaunching() method. I don’t want that, I want to hook up UI-parts with each other using the Interface Builder, not in code.

So, what to do now? I don’t know yet. Let me first deal with a problem that I didn’t tell you about yet. It is in the code of the LeesPlankjeDataSource. I gave my LeesPlankjeDataSource a constuctor that accepts a string array, thereby enabling me to pass in the data that the data source needs to build a UITableView from.

The problem is, that the UISearchDisplayController re-uses my UITableViewController, including the DataSource. When I click search, it first simply overlays my view, but when I start typing in the search box, the ShouldReloadForSearchString () method gets called and that one resets the SearchResultDataSource with a filtered version of my LeesPlankjeDataSource:

public override bool ShouldReloadForSearchString (UISearchDisplayController controller, string forSearchString)
{
	Console.WriteLine("In ShouldReloadForSearchtring");
	controller.SearchResultsDataSource = new LeesPlankjeDataSource(forSearchString);
	return true;
}

And how am I gonna feed this baby with the right data? How is the SearchResultsDataSource going to get a filtered list of the words in my “woordjes.txt” file? I chose to filter by using an overloaded constructor, but I could move that code to a normal method. That allows me to use the other constructor, passing in the data as before in the main.cs:

public override bool ShouldReloadForSearchString (UISearchDisplayController controller, string forSearchString)
{
	Console.WriteLine("In ShouldReloadForSearchString");
	var woordjes = ?????????
	var data = new LeesPlankjeDataSource(woordjes);
	controller.SearchResultsDataSource = data.FilterOn(forSearchString);
	return true;
}

But where am I gonna get the “woordjes” variable from? Should I load the file again, like I did in main.cs? Or maybe my DataSource should know something about the model? In that case I will not pass data from the outside, but let the DataSource find out itself where to get the data. But that is so against the Dependency Inversion Principle (or Inversion of Control)! If classes depend on other classes, these dependencies had best be passed in from the outside, probably on construction time.

Shoot, I love the IoC pattern. Should I let it go, for the sake of simplicity? After all, I argued before that even the MVC-pattern was maybe to much of a burden for the simple applications we build on the iPhone most of the time.

For tonight, I give up. The code you can download contains the solution that goes against IoC, but works none the less.

I would love to hear your ideas about how to build iPhone applications that are tightly coherent and loosely coupled. I know that we can get in some philosophical or religious discussions, but we’ll see what to do then. I just want to learn from you guys, as much as I want to teach you where I can.

P.S.
Thanks to Alex York’s excellent post (see his comment below) I was able to improve on my code. I had seen the idea of nesting the DataSource and Delegate into the UITableViewController before, but didn’t like it then. That dislike mostly came from the fact that you have to inherit from another class. There is no tighter couling between two classes then inheritance, so I believe you should only use it when absolutely necessary. Well, by now I think that it is absolutely necessary to inherit from the classes in the Cocoa framework. It is simply the way you work.

When working on the new solution I also renamed some classes (no more Dutch names, only Dutch words in the data…) and added a class that implements the model:

public class WordsModel
{
	private List _dataStorage;
 
	public WordsModel ()
	{
		_dataStorage = File.ReadAllLines("woordjes.txt").ToList();
		_dataStorage.Sort();
	}
 
	public string[] Data {
		get { return _dataStorage.ToArray();}
	}
 
	public string[] FilterOn(string searchText)
	{
		searchText = searchText.ToLower();
		var result = _dataStorage.Where(t => t.ToLowerInvariant().StartsWith(searchText));
		return result.ToArray();
	}
}

It is the place where the knowledge of words, where they come from and how you filter them, resides.

But Alex’s solution did not solve the problem that is typical of the use of the UISearchDisplayController: you have two instances of your DataSource: the one for your initial view, that just displays all the data (words in my case), and the one that is called upon by the UISearchDelegate when you start to search and filter.

I solved this by implementing a general WordsDataSource that uses the WordsModel and has a constuctor for normal use and for filtering:

public class WordsDataSource : UITableViewDataSource
{
	private WordsModel model = new WordsModel();
	private string[] _dataStorage;
 
	public WordsDataSource()
	{
		_dataStorage = model.Data;
	}
 
	public WordsDataSource(string filter) : this()
	{
		_dataStorage = model.FilterOn(filter);
	}
 
	public string GetAt(int position)
	{
		return _dataStorage[position];
	}
 
	public override UITableViewCell GetCell (UITableView tableView, MonoTouch.Foundation.NSIndexPath indexPath)
	{
		UITableViewCell cell = tableView.DequeueReusableCell("plankje");
		if (cell == null)
		{
			cell = new UITableViewCell(UITableViewCellStyle.Default, "plankje");
		}
		cell.TextLabel.Text = _dataStorage[indexPath.Row];
		return cell;
	}
 
	public override int RowsInSection (UITableView tableview, int section)
	{
		return _dataStorage.Length;
	}
}

It inherits (yep I used the I-word) from UITableViewDataSource so can be called upon by the Cocoa framework when rendering the data for the UITableView.

And then I used that class in two places:

  1. as an internal property in my WordsTableViewController
  2. as a helper-class in the delegate of the UISearchDisplayController.
[MonoTouch.Foundation.Register("WordsTableViewController")]
public partial class WordsTableViewController : UITableViewController
{
    // Constructor invoked from the NIB loader
    public WordsTableViewController (IntPtr p) : base (p)
    {
    }
 
    // The data source for our TableView
    private WordsDataSource TableDataSource
    {
	get { return this.TableView.DataSource as WordsDataSource; }
	set { this.TableView.DataSource = value; }
    }
 
    // This class receives notifications that happen on the UITableView
    class TableDelegate : UITableViewDelegate
    {
	WordsTableViewController parentView;
        public TableDelegate (WordsTableViewController tableViewController)
        {
		parentView = tableViewController;
        }
 
        public override void RowSelected (UITableView tableView, NSIndexPath indexPath)
        {
		string selectedWord = parentView.TableDataSource.GetAt(indexPath.Row);
		using (var alert = new UIAlertView ("Selected", selectedWord, null, "OK", null))
			alert.Show ();
        }
    }
 
    public override void ViewDidLoad ()
    {
        base.ViewDidLoad ();
 
        TableView.Delegate = new TableDelegate (this);
        this.TableDataSource = new WordsDataSource ();
    }
}
[MonoTouch.Foundation.Register("WordSearchDelegate")]
public class WordSearchDelegate : UISearchDisplayDelegate
{
	public override bool ShouldReloadForSearchString (UISearchDisplayController controller, string forSearchString)
	{
		UITableViewDataSource data = new WordsDataSource(forSearchString);
		controller.SearchResultsDataSource = data;
		return true;
	}
}

I’m pretty happy with what I got by now. You can download the new version, if you like.

, , , , , , ,

9 reacties

Building iPhone applications using MonoTouch, part 4: the UISearchDisplayController

In my previous post I wrote about the Interface Builder and things like outlets. Last night (with the help of some colleagues) I cracked one of the more advanced Classes in the Interface Builder: the UISearchDisplayController.

In the previous version of my application I had a UITableView and a UISearchBar. I hooked them up with some code and it worked fine. But I didn’t get the effect that you see in (for instance) the iPod application. When you scroll up,  uncover the search-bar and start typing, the original view is greyed-out. And when your search gives no result, you get a “No Results” message. Like this:

SearchScreenShot NoResults

For that, you need the UISearchDisplayController. This controller does the work of hooking up a couple of UI-elements for you:

  1. The search bar
  2. The view with the results from the search (called the searchContentsController)
  3. The delegate that handles all the events that come from the search bar and the results view (called the searchResultsDelegate)
  4. The data source that provides the data to search in (called the searchResultsDataSource)
  5. Your original view

When you drag a UISearchDisplayController and drop it at the top of your UITableViewController, all the outlets get connected to your controller automatically. Apparently the Interface Builder thinks that your class can play all these roles. This makes sense when you program Objective-C, since that language is quite capable of inheriting from lots of base classes (as is so eloquently explained in the Cocao With Love blog), but asks some more attention when used from MonoTouch.

Designers should not write code, and vice versa

I will explain again what Interface Builder does for you. Maybe you already know, but I had to get used to it, and have to keep reminding myself that you use it to, well,  build interfaces. Nothing else. Interface Builder provides a clean separation between the GUI and the code, and that’s a good thing, right? Right. I love Design Patterns, and I try to convince as much progammers as possible to take at least notice of them. But iPhone apps are mostly very small apps with one or two screens, being very good in just one or two things. Do I need to implement this whole pattern for my simple app? Well, apparently. And so will you, so let me try to help you find out how to do some of these things.

Steps to follow

Begin with a UITableViewController. Then go to the Library Window, the Objects button and drag-n-drop a UISearchDisplayController just at the top of your UITableViewController.
In the MainWindow you will have the UISearchDisplayController added. Click it there, and then go to the Outlets-tab in the Inspector Window. You will see that all the outlets will be connected to your UITableViewController, except for the searchBar-outlet since that is of course connected to the SearchBar.

When you run your app, you will have the Table-View and the SearchBar above it. When you tap the text-field you will see the desired gray-out and the “No Result” if you enter some text. So far so good.

Providing the view with data

Now we need to hook up some of our own code to the events that the UISearchDisplayController fires. Let’s start with some data in our own TableView to filter on.
As said in one of my first posts, data for a view is delivered by a DataSource. In this case a UITableViewDataSource. So add a class to your project that inherits from UITableViewDataSource. Something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class LeesPlankjeDataSource : UITableViewDataSource
{
	private string[] woordjes = new string[] {"aap", "noot", "mies"};
 
	public LeesPlankjeDataSource()
	{
	}
 
	public LeesPlankjeDataSource(string filter)
	{
		woordjes = woordjes.Where(f => f.StartsWith(filter)).ToArray();
	}
 
	public override UITableViewCell GetCell (UITableView tableView, MonoTouch.Foundation.NSIndexPath indexPath)
	{
		UITableViewCell cell = tableView.DequeueReusableCell("plankje");
		if (cell == null)
		{
			cell = new UITableViewCell(UITableViewCellStyle.Default, "plankje");
		}
		cell.TextLabel.Text = woordjes[indexPath.Row];
		return cell;
	}
 
	public override int RowsInSection (UITableView tableview, int section)
	{
		return woordjes.Length;
	}
}

The complete code of this solution is at the bottom of this post.

The class has two constructors. The default constructor (at line 5) is called when initializing our own view, the constructor that takes a string (at line 9) will be called when filtering is started.
The GetCell() and RowsInSection() methods need to be implemented to make your data source work. The implementation is pretty straightforward. The GetCell() method will be called “RowsInSection” times. The call to DequeueReusableCell() is some trick to limit the amount of resources that your iPhone application will use. Just make sure you pass in some string that you reuse a few lines down.

To be able to set this datasource on the table-view we have to have some programmatic access to the view. Well, we did that before in the previous post. Go to Interface Builder, select the AppDelegate in the Library Window, add an outlet and connect it to your UITableViewController. Then you can have code like this in your main.cs:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public partial class AppDelegate : UIApplicationDelegate
{
	// This method is invoked when the application has loaded its UI and its ready to run
	public override bool FinishedLaunching (UIApplication app, NSDictionary options)
	{
		tableView.DataSource = new LeesPlankjeDataSource();
 
		// If you have defined a view, add it here:
		window.AddSubview (tableView);
		window.MakeKeyAndVisible ();
 
		return true;
	}
 
	// This method is required in iPhoneOS 3.0
	public override void OnActivated (UIApplication application)
	{
	}
}

We simply set the DataSource on the tableView to our own DataSource and then add the tableView to the current window. Run your app and you will have some data in your view!

Building the delegate

Now we need some code to handle the events of the search bar. The most interesting event is “ShouldReloadForSearchString()”.

Add a new class to your project that inherits from UISearchDisplayDelegate. The code should look something like this:

1
2
3
4
5
6
7
8
9
10
11
[MonoTouch.Foundation.Register("LeesPlankjeDelegate")]
public class LeesPlankjeDelegate : UISearchDisplayDelegate
{
	public override bool ShouldReloadForSearchString (UISearchDisplayController controller, string forSearchString)
	{
		Console.WriteLine("In ShouldReloadForSearchString");
		controller.SearchResultsDataSource = new LeesPlankjeDataSource(forSearchString);
		return true;
		//return base.ShouldReloadForSearchtring (controller, forSearchString);
	}
}

The first line is interesting. This is the magic that brings your classes into the Interface Builder. By registering the name of your class it will be added to the XIB (although not visible in the designer file). I’ll show you in a minute what you do with this in Interface Builder.

In the override of the ShouldReloadForSearchtring() I instantiate a new data source using the constructor that accepts a filter string. I set this on the SearchResultsDataSource property of the passed in controller object. As you can see in the code of the LeesPlankjeDataSource it will use a Lambda to filter the fixed array of words.

Hooking up the UISearchDisplayController with your Delegate

The Register-attribute on your delegate class makes it available in Interface Builder. So you go to the Library Window, choose the Objects button, then Controllers folder and then the general NSObject. Something like this: LibraryWindow

Drag it to the MainWindow, select it there, go to the Inspector, choose the Identity tab. Now change the class field to the name of your own class. LeesPlankjeDelegate in my case. Your class will not be listed, but that doesn’t matter. When you hit Enter, you’ll see in the MainWindow that both the class name and the instance name have changed. That is just fine.

Now the next magical thing: you have to connect the default delegate of the UISearchDisplayController to your Delegate class. Here is how: select the UISearchDisplayController in the MainWindow, go to the inspector, select the Outlets tab. The first outlet there is called “delegate” and is connected to your TableView. Now remove that connection by clicking the X. Then connect this delegate to your own Delegate class in the MainWindow.

Save in Interface Builder, go to MonoDevelop, run! Type something in the search and “Lo and behold!” it works!

Ain’t live sweet?

If it doesn’t work, feel free to leave a comment. I’ll see if I can help you.

Download the source code

P.S.

The last step is actually more complex than it should have been. If I make my UISearchDisplayController visible to my AppDelegate by adding an outlet, I can do with just one more line of code in my main.cs:

searchDisplayController.Delegate = new LeesPlankjeDelegate();

That way I go one-way: from Interface Builder to MonoTouch. But I thought it more interesting to go the other way too: from MonoTouch to Interface Builder.

, , , , , ,

22 reacties

Building iPhone applications using MonoTouch, part 3 : The Interface Builder

So it’s about time I tell something about the Interface Builder. As I mentioned in my previous post, I fled from the Interface Builder at first. I’m not a designer, so interfaces are hard for me anyway. But I built some in WinForms and in ASP.NET and I got used to the simple system of putting buttons and fields on forms and then hooking them up with the business-logic with things like click-events.

Interface Builder is different. I think the idea is that you use it for nothing else than your GUI. There is no way to put any code anywhere. All handling of UI-events is done in delegates and the trick is to learn how to link your GUI to your code.

I hope you will have a better insight in how to do this, after this post. I learned the most from one of the videos on MonoTouch.Info, by Code Snack. I literally played it frame by frame, carefully watching what he did and what could be learned from the code on the background. Highly recommended.

So, let us build an interface with a tab-bar-controller. You might know this type of application from the default iPhone clock.

Start a new application in MonoDevelop, an “iPhone MonoTouch Project”. Double-click the MainWindow.xib and Interface Builder will start.
The empty window you get is important because it is the window that is referenced from AppDelegate. You will add all your own stuff to it as subwindows. But for now you can ignore it.

Make sure the Library Window is open (Tools / Library) and selected like this:Library Window

Now drag a Tab Bar Controller and drop it on the MainWindow (that looks a bit like a solution explorer) just below “Window”. The MainWindow will look like this:
Main Window And you get a new window looking like this:
Tab Bar Controller

It is not to hard to change some of the settings of the tab bar. Open Tools/Inspector, select the Attributes tab, make sure you have the right part active in the Tab Bar Window and change the Identifier Pull-down to “Search”. You will get a default Search Tab, including the search image.

Search TabMake the first tab a Search tab and the second a History tab. Now save the project and check the MainWindow.xib.designer.cs. Nothing interesting, except for a mapping to the window called “Window”. If you run your application now, nothing interesting.

That is because we have to add our new view as sub-views to the main window. In code like this:

1
2
3
4
5
6
7
8
public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
	// If you have defined a view, add it here:
	window.AddSubview (tabBar.View);
	window.MakeKeyAndVisible ();
 
	return true;
}

But we have no variable named “tabBar”. Well, now we’re coming to the very important part where we hook up our GUI to our code. Interface Builder does that with something they call “outlets”. And defining them is one of the weirdest experiences in your live as a programmer.

Ok, since I want to have a reference in my AppDelegate to the Tab Bar Controller, I go back to Inteface Builder, to the Library Window and select the Classes button. All the way on the top, there is a AppDelegate. Select it. Then look on the bottom of the window. Select the Outlets button. Now you see that the AppDelegate has an outlet called “window” which is mapped in the designer file in MonoDevelop to a property of type UIWindow with the name “window”. That is how the code above can reference a “window” object. We need to add an outlet by clicking the + button. Give it a name like “tabBar”. The change the type to UITabBarController.

Now we have a definition of an outlet. But it is not linked to any UI-element yet. So go to the MainWindow and select the AppDelegate there. Now go to the Inspector Window and select the Connections tab. You will see that the connection from the tabBar outlet is still open:
Defined OutletsNow comes the magic. You drag the open circle to the Tab Bar Controller window. While getting there you will notice that only windows that are of the right type (UITabBarController) will be an acceptable drop-target. Now drop it, save it and go to MonoDevelop. In the designer file you will see that a new mapping is made. If you change the code in your main.cs to reflect the code above and run your application, you will have your tab bars!

Ok, so far for this post. Next post I will add a search-bar to the search window on the search tab and try to hook them all up to each other and to the code.

, , , , ,

3 reacties

Building iPhone applications with MonoTouch, part 2 : The AppDelegate

This is part 2 of a series. In the first post I said something about the application structure.

A word about Twitter

I’m going to digress a little before telling you more about iPhone application structure. It is not essential for this series, but it is essential to completely describe the adventure that this first application brought on me.

When I found out about the MonoTouch project, it was in Beta and you had to apply to be admitted. I filled in the form (from my iPhone, just to impress them) and then waited. Nothing for a couple of days. I applied again, just to make sure you know. Nothing. Now I’m a modern guy, so I tweet. I tweeted my frustration (in Dutch), since I really wanted to get started. But hey, what where the 3 followers I have gonna do about that? Then it turned out that this guy Joseph Hill, somehow monitors all tweets in the world for the MonoTouch keyword. Joseph is one of the people in the MonoTouch project that is really a Person. He pulled some strings and presto! I got my Beta-account.

For me, that’s just amazing. I didn’t think that Twitter would give me much more than just the latest tips from Scott Guthrie, but this is a totally new way to bring people together and build communities.

The AppDelegate

When you create a new iPhone solution in MonoDevelop, you get a couple of things:

New Solution

New Solution

  1. A xib file called MainWindow.xib. This is where your user-interface is defined. It is an XML file that can be used by the Interface Builder. Simply double-click it and the Interface Builder opens up. More about the Interface Builder later. MonoDevelop monitors the file and regenerates the accompanying designer file when the XIB is changed by Interface Builder. The designer file maps the elements from the user-interface to the classes in your project.
  2. A main.cs that contains the entry-point to your code. There is  a partial class called AppDelegate that is mapped to the main window of your UI. The most important method there is “FinishedLaunching”. It gets called when the iPhone is done with all the stuff it does when loading an application. The name is a bit misleading. Your application is definitely not done launching, at best it is done loading. All the stuff that you need to do yourself still has to happen. Like loading some files, initializing your controllers, setting-up your model classes.

Loading your application

There’s more to say about the loading process. Since it takes some time before you even get control about what happens, you have the option to show an image while loading. Add a file to your project with the name “Default.png” and set it’s properties to “Build Action – Content” and it will be picked up by the loader. Your supposed (according to the designer guidelines) to use an image of your app in action, but it is often abused to show a company logo or something. Some applications make a screen-shot of themselves when the application closes and save that as Default.png. That way, the next time you start your app it looks like it quickly continues where it left off.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// The name AppDelegate is referenced in the MainWindow.xib file.
public partial class AppDelegate : UIApplicationDelegate
{
	// This method is invoked when the application has loaded its UI and its ready to run
	public override bool FinishedLaunching (UIApplication app, NSDictionary options)
	{
		Console.WriteLine("Launched");
 
		window.AddSubview(yourViewHere);
		window.MakeKeyAndVisible();
		return true;
	}
 
	// This method is required in iPhoneOS 3.0
	public override void OnActivated (UIApplication application)
	{
	}
}

You should not be doing too much work in this method. The loader times the duration of this method and kills your application when it takes more than 10 seconds. Or so they say, I never tried it out.

You can use this method to build up your user-interface in code. I went that way first. I had such a hard time getting my head around the Interface Builder that I decided to drop it and build my interface by hand. That worked reasonably but caused unexpected crashes. I knew it had something to do with the way I hooked up the different views, so I went back to Interface Builder and tried and tried and tried. I got it, more or less, and my interface (using a tab-bar) is now stable. In the next episode I will dive into the Interface Builder.

, , , , ,

1 reactie

Building iPhone applications using MonoTouch, part 1 : Application Structure

I finished my first iPhone app this weekend. it is not a very impressing application, but it does what I meant it to do and that is to show movies with Dutch Sign Language coming from the website of the Dutch Gebarencentrum.

Developing for the iPhone is exciting. Well, let me re-phrase that: the result of your development for the iPhone is exciting. Mmmmh, let me re-phrase that again: it was a helluva job to build a working iPhone app, and now that I know how to do it I’m excited!

This post is the first of a couple of post I’m planning to do on development of iPhone applications with .NET. There’s simply too much to learn and to tell to do it all in one post. These posts will not only be about programming C#, but also about design principles, open-source programs, Twitter.

Where do you start?

As a .NET developer you have two choices to program for the iPhone:

  1. You learn the Objective-C programming language and the XCode development environment
  2. You use MonoTouch and MonoDevelop

I started out with the first option, since the second was not available at that time. I found it really hard. Using a c-like syntax is not the hardest thing, but I surely wasn’t used to manage my own memory any more! I got really frustrated since I also had to learn all the other things I’ll talk about in a minute.

The solution came in a podcast from DotNetRocks titled “Rory does iPhone” in which Rory Blyth raved against Objective-C. In that podcast there was a short mention of an open-source initiative called MonoTouch.

Mono

That changed my world radically. I went out looking for the Mono guys and found a very mature platform and active community. if you don’t know: Mono is an open-source initiative that brings the .NET framework to a lot of other platforms, especially the Unix-look-a-likes.
I had heard about Mono before, but always thought it was a project that was way behind the development of the .NET framework. You know, like Microsoft is releasing .NET 4.0 and the Mono guys are proud to announce they now support 2.0! Nothing like that! Mono is on .NET 3.5 and preparing for the changes that 4.0 will bring. They also have a very nice IDE called MonoDevelop that looks a lot like Visual Studio.

With MonoDevelop developing applications on the Mac is so straightforward that I never go back to my VMWare installation with XP and VS2008 to do some quick development. If you think about porting your application (since not all that is available on Windows is there on Linux too), install their Mono Migration Analyzer add-in.

And they have MonoTouch. On the surface it is just a wrapper around the CocaoTouch library that you use to program UI’s on the iPhone.

But is is also a very special compiler that pre-JITs (the call it Ahead Of Time compilation) the entire application. Why? The iPhone OS will not allow you to run a virtual machine. Ever wondered why there is no Java or Flash on the iPhone? They cannot run since they depend on their own VM.
MonoTouch circumvents this problem by generating native code, removing all the unused libraries, classes and methods and then building a Mac App package from that.

What do I have to learn?

When you want to build your own application, you will at least have to learn about:

  1. The structure of iPhone apps
  2. The Cocao Touch library
  3. The Interface Builder
  4. Debugging in XCode
  5. Signing your application
  6. How to distribute your application

I will try to tell you about all of these subjects in different installments.

The structure of an iPhone app

It is essential to know what the iPhone expects from you and how the Cocao Touch library supports that. It is probably  way different from the way you worked in C# and WinForms, and it takes some time to get used to finding out where to put your application logic.

The Cocao Touch library is full of Design Patterns, but the most pervasive, noticable, visible and wonderful is The Model View Controller. Below is an image from the Mac Development Library:

MVC

MVC

This post is not about Design Patterns, so I will not explain how the MVC pattern is supposed to work. The image is just their to help me explain which classes you will have to inherit from.

Cocao development is about inheriting from the classes that wire up the application for you. That means that you only have to override the methods that are of interest to you, but it also means that you essentially have no way to stray from this setup. You use the Cocao classes or you end up building your own library.

These are the classes that implement the MVC pattern for the often-used TableView:

  1. UITableView
  2. UITableViewDataSource
  3. UITableViewDelegate
  4. UITableViewController

The UITableView is in the NIB: the file that is generated for you by the Interface Builder and that holds all the GUI elements.

The UITableViewDataSource holds the data that is displayed in the table. It’s methods are called by the Controller to fill the cells in the table (e.g. GetCell, RowsInSection).

The UITableViewDelegate implements methods for dealing with user-actions that are performed on the view, like “RowSelected” when (yep) a row in the table is selected.

The UITableViewController is the man-in-the-middle. It sits between the DataSource and the TableView, and does things like passing the DataSource filtered data when some search criterion is entered and then telling the TableView to reload with this new data. The controller can use your own model to get this filtered data.

So far for this installment. Next time I will show some code and tell about the AppDelegate, the object that functions as the heart of your application since it receives a lot of interesting messages like “Hey you’re app is started!”.

, , , , ,

9 reacties

Nieuwe iPhone applicatie gelanceerd: Quote eetgids

Op 1 oktober was het zover, de Quote eetgids staat in de Apple Appstore! Met de Quote eetgids kan je op eenvoudige wijze restaurants in de buurt vinden en beoordelen. Dit op basis van je huidige lokatie die met behulp van GPS wordt vastgesteld. Heb je andere voorkeuren? Alleen met gelegenheden met michelinster? Of na een heerlijke dag varen, aanleggen bij de steiger met zicht op je blinkende jacht van een voortreffelijk menu genieten? Check de Quote eetgids!

installeer de Quote eetgids Ontwerp: luminis live
Technische
realisatie: luminis software development

, , , , , , , ,

1 reactie