Edward Benson

Technology and Society

Using Apple’s UISearchDisplayController with Three20

without comments

Joe Hewitt’s Three20 project is a great set of libraries for iPhone development, but one of the inevitable consequences of using it is that Apple eventually releases official versions of some of the same “missing widgets” found in Three20. One such example is the search functionality in tables.

I have been using Three20 for an exciting project I’m working on over the summer, but also wanted to leverage the new search functionality of the iPhone OS 3.0 instead of the Three20 search feature. It took about a day of poking around the code-base of both, but ultimately only a few changes to the code, which I’ll describe here.

Step 1: Implement the search delegates in your TTTableViewController

In your TTTableViewController interface, tack on the UISearchDisplayDelegate and UISearchBarDelegate interfaces to say you’ll be implementing those. They will let the search bar and controller send your controller events to let it know it is taking over.

Step 2: Add the search bar to your table header

In your loadView method, create a new UISearchBar object and add it to your table’s header, like so:

- (void)loadView {
  // [SNIP]
    UISearchBar *searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, self.tableView.frame.size.width, 0)];
    searchBar.delegate = self;
    searchBar.showsCancelButton = YES;
    [searchBar sizeToFit];
    self.tableView.tableHeaderView = searchBar;
    [searchBar release];
}

Step 3: Add a SearchDisplayController to your controller

In the same loadView method, create a new UISearchDisplayControllerand add it to self:

- (void)loadView {
  // [SNIP]
   UISearchDisplayController *searchDisplayController = [[UISearchDisplayController alloc] initWithSearchBar:searchBar contentsController:self];
   [self setSearchDisplayController:searchDisplayController];
   [searchDisplayController setDelegate:self];
   [searchDisplayController setSearchContentsController:self];
   [searchDisplayController setSearchResultsDataSource:self.dataSource];
   [searchDisplayController release];
}

Notice above that you are pointing the SearchDisplayController at several different items: the UISearchBar from before, self, and also your TTTableViewDataSource.

Step 4. Implement the required delegates

Next we’ll implement the required delegate methods that will be called when the user interacts with the search bar. Notice below that we’re using these methods to essentially pass information through to the data source.

- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope {
	[self.dataSource filterContentForSearchText:searchText scope:scope];
}	

- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
    [self filterContentForSearchText:searchString scope:
	 [[self.searchDisplayController.searchBar scopeButtonTitles] objectAtIndex:[self.searchDisplayController.searchBar selectedScopeButtonIndex]]];

    // Return YES to cause the search result table view to be reloaded.
    return YES;
}

- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchScope:(NSInteger)searchOption {
    [self filterContentForSearchText:[self.searchDisplayController.searchBar text] scope:
	 [[self.searchDisplayController.searchBar scopeButtonTitles] objectAtIndex:searchOption]];

    // Return YES to cause the search result table view to be reloaded.
    return YES;
}

- (void)searchDisplayControllerDidBeginSearch:(UISearchDisplayController *)controller {
	DKSearchableDataSource *ds = self.dataSource;
	[controller setSearchResultsDelegate:self.tableView.delegate];
	ds.searchActive = YES;
}

- (void)searchDisplayControllerDidEndSearch:(UISearchDisplayController *)controller {
	DKSearchableDataSource *ds = self.dataSource;
	ds.searchActive = NO;
}

Important! Notice the setSearchResultsDelegate call above. This occurs here instead of the loadView method above because the table delegate hasn’t yet been created when we’re still inside of loadView — if you were to set it up there then selecting search result cells wouldn’t trigger a callback.

Step 5. Modify your data source to be aware of search

Finally, we need to modify our data source to be aware of this new “search mode.” I did this with a pretty simple fix: I created a boolean property named searchActive that is set by the owning controller (see the above code). Then, in all the important methods, I put in a simple if..else statement that returned one value for search mode results and another value for normal usage. Here’s an example:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
	if (self.searchActive && (self.searchText != nil)) {
		return self.filteredItems.count;
	}
	else {
		return self.items.count;
	}

}

In the above conditional, I check for searchText to see if the user has begun searching yet. If they haven’t I want to display all results.

Finally, I need to implement the actual search method, which is simply passed through from the controller class.

- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope {
	[self.filteredItems removeAllObjects]; // First clear the filtered array.
	self.searchText = searchText;

	/*
	 Search the main list for products whose type matches the scope (if selected) and whose name matches searchText; add items that match to the filtered array.
	 */
	for (id *item in _items) {
		NSComparisonResult result = [[item searchText] compare:searchText options:(NSCaseInsensitiveSearch|NSDiacriticInsensitiveSearch) range:NSMakeRange(0, [searchText length])];
		if (result == NSOrderedSame) {
			[self.filteredItems addObject:item];
		}
	}
}

Conclusion

I left a lot of explanation out here, but I hope this is enough to get you started on using Apple’s “official” search functionality with the Three20 library. Leave a comment if you have any questions or need a bit more explanation of the code and I’ll be glad to amend the post.

Written by Ted

June 29th, 2009 at 3:27 pm

Wordpress LaTeX Support

without comments

If you can see this

\sum_{i=0}^{10} i

And this

A_{m,n} = \begin{pmatrix} a_{1,1} & a_{1,2} & \cdots & a_{1,n} \\ a_{2,1} & a_{2,2} & \cdots & a_{2,n} \\ \vdots  & \vdots  & \ddots & \vdots  \\ a_{m,1} & a_{m,2} & \cdots & a_{m,n}  \end{pmatrix}

Then LaTeX is working!

Written by Ted

June 25th, 2009 at 10:46 pm

Posted in Computer Science

What is Machine Learning

without comments

I’m interested in Machine Learning, but still quite a newbie in the field, so I thought I would start posting articles about it to force myself to read more and begin synthesizing the information in my mind. Since this is the first, I’ll start with the basics: what is Machine Learning, anyway?

Machine Learning has its origins in the Artificial Intelligence community but it is actually a different branch of Computer Science than what one often thinks of as AI. When people say they are  doing “Artificial Intelligence,” it often refers to the quest to make computers more humanlike — able to think, reason, emote, etc. Machine Learning, on the other hand, uses a slightly different set of tools to solve basic engineering problems that humans alone can not solve. Machine Learning is specifically focused on problems that are easier for a computer to learn how to solve than for a human to figure out how to solve.

That characterization might sound a bit strange, so here is an example: You are given 10,000 patient records involving heart disease patients over the past five years and asked to find out if there are any drug combinations that appear to be having adverse affects. With that quantity (and complexity) of data, it is near impossible for a human to approach the task of answering the question. Using Machine Learning, the human can instead teach the computer, how to learn how to find the answer, and then let it loose. It is sort of like meta-math: you teach the computer how to solve the problem of solving a problem.

Here is a breakdown of the categories of problems that you can solve via this method:

  • Supervised Learning involves taking an existing set of data for which you have example inputs and “answers”, and then learn how to guess a new answer from a new input that hasn’t been seen before. This can be divided into two further cases based on whether your answer-space is continuous or discrete:

    • Regression is performing supervised learning on a continuous data set. You might be trying to predict weight based on a person’s age, for example. In this case, you would train your algorithm on an example set of weights and ages, and then you would predict future weights using just an age by itself.
    • Classification is performing supervised learning on a discrete data set. You might be trying to predict a person’s favorite ice cream flavor based upon a number of other attributes about them. Your training set consists of multiple people with those predictive attributes, along with their choice of ice cream flavor.
  • Unsupervised Leaning is the act of solving a problem for which there is no existing set of solutions to provide the computer as examples. In unsupervised learning, the question you are asking the computer is, “is there any interesting structure in this data?” The typical example of this type of learning is clustering, the act of grouping items into different buckets, without knowing in advance what those buckets are. You might be trying to explain the habitat of Canada Geese, for example, and have a large data set that consists of their location at randomly selected time instants. Using unsupervised learning, the computer might cluster these locations into two general categories: Canada and Florida. While this example could easily be performed by the human eye, remember that computers can deal with multiple, sometimes infinite-dimensional data that no human could ever process.
  • Reinforcement Learning can be thought of as learning that takes place gradually, with feedback after each step. Whereas supervised and unsupervised learning uses a data set presented in its entirety at the beginning of the problem,  with reinforcement learning the computer is presented instead with a goal (described mathematically, of course). The computer then takes actions (also described mathematically) which generate either positive or negative feedback. This feedback is incorporated into the computer’s strategy which evolves over time as it learns to meet its goal. An example of feedback learning is the autopilot on an airplane. The goal is to keep the airplane flying to its destination in a steady manner. The actions the computer can take consist of altering air speed, pitch, yaw, and rudder controls, and the feedback the computer receives is a combination of how the plane is actually performing versus how the autopilot settings are asking it to perform.

So that is my quick and dirty run-down of Machine Learning. I’m no expert, so if there are problems with this post please leave a comment and I’ll correct them. Either way, I hope this is the start of a series of useful articles explaining some of the basic principles and techniques of the field.

Written by Ted

June 25th, 2009 at 10:00 am

Posted in Machine Learning

Tagged with ,

Custom primary keys with ActiveRecord

without comments

I’ve been writing a lot of Rails/iPhone data synchronization routines lately, and ran into a corner of ActiveRecord I’ve never encountered before despite having used it since the original release of Rails: custom primary keys. So I thought I’d share what I found out here.

As you know, ActiveRecord’s default is to always tack on an auto-incrementing integer field called id as your primary key. For most web use, this default behavior is fine, but in Objective-C id is a reserved word. I wanted to have my Objective-C models match the Rails models perfectly (to avoid a translation layer), so I needed to change my id column to some other name. After a bit of experimenting, I found this is relatively easy. It just takes two steps:

One: Change your migrations

Use the :primary_key option in your create_table command to specify the new primary key name.

class CreateUsers < ActiveRecord::Migration
  def self.up
    create_table :users, :primary_key => :dkid do |t|
    ...
  end
  ...
end

Two: Tell your ActiveRecord models what the primary key is

This is the step that I missed the first time around, and it is the step that, if you forget it, will cause all hell to break loose with your ActiveRecord associations and some other subtle workings of the framework. All you need to do is use the set_primary_key macro from inside your object to tell it the name of the custom primary key:

class User < ActiveRecord::Base
  set_primary_key :dkid
  ...
end

At this point, as far as I can tell, everything else works as normal. Your association foreign keys still default to ModelName_id, even though the primary key is no longer named id, and everything works as you would expect. I'll update here if I find out otherwise.

Written by Ted

June 12th, 2009 at 2:33 pm

Marvin Minsky on the AI Winter

without comments

I went to the morning half of the Living Heritage AI Workshop held at CSAIL today and it turned out to be a cool get-together of many of the founders of artificial intelligence from the MIT AI Lab heydays. Marvin Minsky spoke for a while, and a small, but interesting, part of his talk was a rundown of why he thought AI research essentially came to a halt in the 80s: because focus changed from solving small, focused problems to trying to come up with a single approach to solve all problems. Here is the rundown he gave of these one-size-fits-all approaches, and their shortcomings:

  • Neural Networks – tend to get stuck on local peaks
  • Rule-based Systems – don’t yet use enough reflective layers
  • Baby Machines – all, so far, have failed to keep growing
  • Statistical Methods – fail to explain what causes exceptions
  • Genetic Programs – fail because they lack explicit goals
  • Situated Action – needs higher-level representations
  • Formal Logic – can’t exploit reasoning by analogy
  • Fuzzy Logic – cannot support reflective thinking
  • Simulated Evolution – Fail to learn the causes of failures
  • Algorithmic Probability – More general, but needs approximations.

He followed with the comment: “Physicists prosper by showing where old theories fail. AI-researchers seldom publish their programs’ faults.”

Another cool tidbit is that he said he never remembered technically admitting anyone to the AI Lab back in the day. They had a lot of funding at the time, and people would just show up from universities overseas, and sometimes they would stay for a week and sometimes they would stick around for good.

Written by Ted

June 11th, 2009 at 2:35 pm

A Simple Extension for Microformat & RDFa Table Support

without comments

Cross-posted on the Haystack Blog.

Microformats and RDFa provide a way to interweave semantic markup within a web document so that structured information can be more easily extracted. Both Microformats and RDFa follow the hierarchical model of HTML: structured data to be extracted may exist spread across several layers of the DOM
hierarchy. A pseudocode example of this is below, where we see that the statement <Jefferson eats Hamburgers> is spread across three levels of the DOM Tree.

<div subject="Tom">
<div property="eats">
Hamburgers
</div>
</div>

A wrinkle in this hierarchical mindset is the fact that a great deal of structured information on the web lives in the one HTML construct that does not fit a hierarchical representation: tables.
Consider Wikipedia, as just one source of structured data virtually begging to be annotated with RDFa. On many Wikipedia pages one of the first things that catches a visitor’s eye is the “Info Box”. This is a small box containing a structured summary of the key factual items on the page. Equally important is the way in which Info Boxes are populated: they begin their life as templates — the “Capital City” or “Baseball Player” template, for example — and all the Wikipedia contributor has to do is fill in the empty field values.
Microformats and RDFa are able to mark up tables, such as these Info Boxes, but they do so in a suboptimal way: they require repetition of semantic markup across each row (or column, depending on the orientation of the table). This:
  • Is redundant from a representational standpoint
  • Clouds the ability of a data enhanced web browser to infer that entire rows and columns of the table talk about the same thing.
  • Forces the template writer to put markup within the table body, rather than on its column and row declarations
To cure this, here is a simple proposal to add table support to both Microformats and RDFa. It is compact, needing only a single sentence to describe:

When parsing the DOM to extract embedded data and a <TD> element is encountered, treat its corresponding <COL> element as if it were the DOM parent of the <TR> element for that cell.

The problem with tables is that a table cell (TD) is contained in HTML by its row (TR) but not its column (COL) because of the way HTML works. This means that when we use tables and microformats/RDFa together, we’re stuck: we can put information across each row, but not down each column. So the proposal is to make a special case for table columns when it comes to pulling out structured information in the cells: even though the cell isn’t technically contained by the column element, pretend that it is.
Let’s see how this cleans up the representation of a simple table of president names. This table has one president per row: Thomas and John.
Here is a pseudocode example of how microformats/RDFa currently require such a table to be marked up. Notice how the “first” and “last” properties needed to be repeated across each row.

<TABLE>
<TR><TH>First</TH><TH>Last</TH></TR>
<TR subject="tj"><TD property="first">Thomas</TD><TD property="last">Jefferson</TD></TR>
<TR subject="ja"><TD property="first">John</TD><TD property="last">Adams</TD></TR>
</TABLE>

If we allow structured content to live in the <COL /> elements, then we do not need this repetition:

<TABLE>
<COL property="first" /><COL property="last" />
<TR><TH>First</TH><TH>Last</TH></TR>
<TR subject="tj"><TD>Thomas</TD><TD>Jefferson</TD></TR>
<TR subject="ja"><TD>John</TD><TD>Adams</TD></TR>
</TABLE>

When parsing either of these two tables for data, we extract the same information:
  • :tj :first “Thomas”
  • :tj :last “Jefferson”
  • :ja :first “John”
  • :ja :last “Adams
Tables are all over the web, and they make great templates to assist users in entering structured information. This small change to the semantics of microformat and RDFa parsing should allow a cleaner syntax for publishing both data and data-templates, easing the adoption of the respective
formats.

Written by Ted

May 19th, 2009 at 10:03 am

Google Voice & SMS Charges

without comments

I just got a Google Voice account, and while most people are citing the “ring anywhere” feature as the killer one, I think it is going to be international calling. Grace just used my cell phone (patched through Google Voice) to call home to Taiwan: the quality of the call was decent, and it only cost 2c per minute.

Now let’s compare that against SMS messaging in the US. I just got my monthly phone bill and was charged about $10 for SMS messaging last month. AT&T charges me 20c per message.

For the cost of a single text message sent over AT&T’s network, I can call Taiwan for 10 minutes — from my cell phone — using a VoIP setup.

Written by Ted

March 25th, 2009 at 10:22 pm

Posted in The Interwebs

Small Business Goes Digital

without comments

I just read about the Amazon Digital Text Platform the other day, and I really feel like we’re reaching a tipping point for some fundamental changes in the possibilities for small and home-grown business on a lot of fronts.

The web did a lot to “flatten the world,” to use the buzzword, but it didn’t go far enough. While a Joe Schmoe in the middle of the country could suddenly launch his own web email service to challenge Google, Joe could still never compete when it came to the distribution, marketing, accounting, etc etc of the big companies in the room.

Enter the concept of the AppStore. Whether Apple realized it at the time or not, I think they pushed a snowball off a cliff that is forever going to change content distribution, at least in America. Suddenly Joe Schmoe doesn’t have to worry about distribution & accounting — it’s all handled by Apple, of course for a 30% cut. And now Amazon enters with the same pitch: give us your text, professional or not, and we will handle the sales and distribution for you.

As traditional publishing industries shudder at the looming shadow of the internet approaching them, I wonder if a new, much larger ecosystem of content publishing is about to reveal itself. One in which average folks write small bits of content and charge modest fees — you give me $0.99, and I give you an essay that I spent one month working on. With the scale of the internet, everyone wins.

Written by Ted

March 4th, 2009 at 2:13 pm

Posted in Business

Tagged with , ,

Datapress launch in 3..2..

without comments

I’m excited.

datapress1

Written by Ted

March 3rd, 2009 at 12:42 am

Posted in Haystack

Tagged with ,

90s and early 00s an Anomaly?

without comments

I’m no stock analyst, but when you look at the history of the DOW on Google finance, you have to wonder if the stock market isn’t crashing, but just resetting back to where linear growth would (should?) have taken it.

dow

(red line added by me)

Kind of scary for someone like me who has most of his savings in stocks bought between 2004 and 2007.

Written by Ted

March 2nd, 2009 at 1:15 pm

Posted in Business

Tagged with ,