Archive for the ‘iPhone’ Category

iPhone voice memo to MP3

August 5, 2010

Today I tried the iPhone Voice Memos for the first time and recorded a meeting that lasted for 55 minutes. To get access to the voice memo file you need to sync the iPhone with your computer using iTunes. iTunes has a special folder called Voice Memos. The resulting file was in m4a format and it was about 110 MB. Way too large to share. iTunes does not offer a way to compress audio files. You can use GarageBand to convert it to a mono MP3 and in my case the resulting file was only 12 MB (almost 100 MB smaller – not bad).

In GarageBand select Podcast project, and from the Audio tab drag the m4a, then choose the Save Podcast to Disk from the GarageBand’s Share menu. There is no need to download, try or buy one of the countless audio converters that you may find on the web. GarageBand does a great job.

UITextField: how to dismiss the Number Pad keyboard

July 11, 2010

By default the Number Pad keyboard unlike the default keyboard does not have a “Done” button. I tried a number of different techniques to dismiss the keyboard, e.g., set the UITextField’s delegate to the ViewController and then add this method:

- (void)textFieldDidEndEditing:(UITextField *)textField
    [textField resignFirstResponder];

But this didn’t work. The method would get called, but the focus still remained in the UITextField. Instead, I chose to use the touches methods to dismiss the keyboard. This allows the user to touch anywhere outside of the text field to dismiss the keyboard. Here is a method that will dismiss the keyboard:

-(void)touchesBegan: (NSSet *)touches withEvent:(UIEvent *)event
       // do the following for all textfields in your current view
	[self.my_text_field_1 resignFirstResponder];
       // save the value of the textfield, ...

Mapping cellular signal strength to 5 bars

July 4, 2010

By now you may have heard about the reception problems with iPhone 4. Apple has mentioned that the real problem has been with the way they mapped signal strength to the famous AT&T 5 bars icon (where 5 bars denotes excellent reception and no bars means very poor reception). Recently I had tried to solve the same problem so here is the mapping that I used. I wonder what Apple is now using.

But first a few words on signal strength and its unit. The cellular signal strength is represented in -dBm: the power ratio in decibels of the measured power referenced to one milliwatt. The useful range is somewhere between -50dBm to -110dBm. The smaller the number the worse the signal. So -50dBm is much better than -110dBm. A 3 dB increase represents doubling the power. I’ve not researched if it is possible to get the the actual signal strength using the iPhone SDK. But I’ve been using the Tetlit cellular modems and there are a couple of AT commands that provide this information: MONI and CQS. The AT command MONI returns the received signal strength in dBM. Based on testing, I’ve seen MONI returning signal strength anywhere from -55dbM to -110dBm depending on location. At lower dbms, e.g., -109 or above, you can definitely still send SMS but the quality of reception is lower (more bit rate errors) and I’m not sure if you can hold a conversation at these dBm levels.

The AT command +CQS maps the signal strength into a signal quality number between 0 to 99 as shown in the table below:

Signal Quality dbM Power (milliwatt)
0 -113 or less 0.0000000000050119 or less
2 to 30 -109 to -53 0.0000000000125893 to 0.0000050118723363 (2 dBm per step)
31 -51 or greater 0.0000079432823472 or greater
99 not known or not detectable

AT&T converts the reception signal strength to a number between 0 to 5. The famous bars icons are used to denote this: 5 bars means excellent reception and 0 bars means almost no reception.

According to the CSQ command mapping -113 dBm maps to 0 and -51 is the best you can get. The difference between these two is about 62 dBm and if you divide 62 dBm range by 6 you get 10.3 dBm per step which must be more or less the dbM interval that AT&T uses to map the signal strength to bars. Based on this approach here is the rounded dBm table mapped to a number between 0 to 5.

dbM Signal Quality
-60 or greater 5
-61 to -73 4
-74 to -85 3
-86 to -98 2
-99 to -110 1
-111 or less 0

But if you use this it is very rare to get 5 bars, so it is possible that most cell phones will reduce the dBm interval mapping to bars and increase the lower range so that -75dBm or greater maps to 5 bars and end up with something like this:

dbM Signal Quality
-75 or greater 5
-83 to -74 4
-95 to -82 3
-105 to -94 2
-110 -104 1
-111 or less 0

Sharing SQLITE connection on iPhone threads may leave you hanging

June 17, 2010

iPhone SDK makes asynchronous operations really easy to use. There is no excuse for not making an application where the UI freezes whilst you’re downloading a URL or running a time-consuming SQL query. Here is an example of creating a background task (using NSInvocationOperation class) that you could call once the UI view has been initialized. In this example, the method init_data_details will be assigned its own thread and it will run in the background leaving the main thread for accepting user input. You’ll need to create a queue which here I’ve done in the Application Delegate class (essentially as a global variable that can be accessed from all views).

AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSInvocationOperation *operation = 
    [[NSInvocationOperation alloc] 
[appDelegate.queue addOperation:operation];
[operation release];

In the init_data_details, I was running SQL queries on a local SQLITE3 database. To improve the performance of SQLITE, I was reusing a connection and all prepared statements. In case of memory warnings, I closed the connection and sqlite3_finalize all prepared statements. The problem was that I was sharing the same connection across multiple threads. This resulted in mysterious crashes with SQLITE3 stack traces that always ended up at sqlite3VdbeMemGrow. The fix in this case was to open a new connection (and prepare new statements) for all SQL accesses that were taking place in the background thread. Here is the outline of the operation:

- (void) init_data_details
// SQL is my encapsulation of the access to SQLITE3
// It creates a connection, handles open/close and 
// prepare statements

	SQL *sql2 = [[SQL alloc] init];
// pass this new connection to methods that need to access 
// the database in the background thread.

	NSMutableArray *data_array =
        [Someclass/object method  connection:sql2];

// process the data, update the UI, ...
// Here updating a UITableView object called
// overview_table

	[overview_table reloadData];

// Close connection, finialize prepare statements 
// for this connection, ...
	[sql2 close_connection];
	[sql2 release];

UIColor using RGB macro

May 30, 2010

The default OS X color picker does not show you the RGB color code. There are a number of other color pickers that you can install and they will extend the standard color picker giving you access to this information. I use the Rubicode’s RCWebColorPicker.

Once you’ve access to the RGB values you can use a C macro to define a shortcut for passing this RGB and getting a UIColor. Here I’ve defined two macros: RGB and AC_BLUE. The first takes three arguments and will yield a UIColor object. The AC_BLUE is an example of how you could use this macro to set the color palatte for your objective-C application.

You can define these macros in your project’s MyProject_Prefix.pch file so that they are available to all of the classes in your application.

#define RGB(r, g, b) [UIColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:1]
#define AC_BLUE RGB(0x00, 0x95, 0xD2)

Books on iPhone

May 10, 2010

I’ve recently started using my iPhone to read reference books. I bought a number of books on Amazon, but the Kindle app is kind of annoying for reference material. For example, there is no search, you cant jump to the Index section, the table of content is just a long list of long links making it difficult to scroll through the TOC pages. But there is a new class of reference material for the iPhone that take advantage of the native iPhone controls to provide a much more enjoyable and useful experience. By far the best such apps that I’ve seen to date are SDK IQ by, 7-Steps to a successful Startup by Naeem Zafar, and Presenter Pro app.

MYSQL to SQLITE for iPhone

May 9, 2010

Today I had to migrate a MySQL table to SQLite so that I could use it in an iPhone app. The process is simple, you can export the MySQL table and then import it in SQLite. I found the following shell script in the MySQL site (I think), but the resulting file could not be imported in SQLite, since I had used the MySQL COMMENT to document each of the columns. SQLite does not understand column comments. So here is the updated script that makes the MYSQL dump work with SQLite.


/opt/local/lib/mysql5/bin/mysqldump --compact --compatible=ansi --default-character-set=binary -uUSERNAME -pPASSWORD DATABASE TABLE  | 
sed -e "s/COMMENT '.*',/,/" |
grep -v ' KEY "' | 
grep -v ' UNIQUE KEY "' | 
perl -e 'local $/;$_=<>;s/,\n\)/\n\)/gs;print "begin;\n";print;print "commit;\n"' | 
perl -pe ' 
if (/^(INSERT.+?)\(/) { 
' > db.sql 

You must substitute the USERNAME, PASSWORD, DATABASE and TABLE with the values for your project.

Next, you need to load this dump file into SQLite, issue the following command:

cat db.sql | sqlite3 db.db

This will create a SQLite database in a file called db.db. Now you can add the file db.db to your iPhone project, plus add the SQLite3 iphone framework and finally you’ll be ready to use the database from Objective-C.

UITableView in UIViewController

May 3, 2010

There are times when you want to add a UITableView to a UIViewController (without having to use a UITableViewController). To do this, you’ve to make sure to override the implementation of a number of methods in the delegate and data source classes to get the table to work as expected, i.e., to support deletion and insertion of rows. You’ve to remember to make the following changes:

You need to implement some of the methods of the UITableViewDelegate and UITableViewDataSource classes. Don’t forget to declare them in the interface definition. If you’re using the Interface Builder, make sure that you connect the table view to my_table. I forgot to do this step causing much frustration. If you forget this step, the table view object is not created, but calling methods on it don’t fail so you don’t have a easy null pointer exception to help you find the cause.

How to tile an image using iPhone SDK

April 17, 2010

To tile an image on a UIImageView, you’ll need to use CGContextDrawTiledImage function. Here is a code snippet to tile an image called wave on the imageView object that you’ve defined.

- (void)viewDidLoad {
        [super viewDidLoad];
	UIImage *wave = [UIImage imageNamed:@"wave-bg.png"];
	CGSize imageViewSize = imageView.bounds.size;

	CGRect imageRect;
	imageRect.origin = CGPointMake(0.0, 0.0);
	imageRect.size = CGSizeMake(wave.size.width, wave.size.height);
	CGContextRef imageContext = UIGraphicsGetCurrentContext();
	CGContextDrawTiledImage(imageContext, imageRect, wave.CGImage);

	UIImage *finishedImage = UIGraphicsGetImageFromCurrentImageContext();
	imageView.image = finishedImage;

Sharing objects between view controllers

April 17, 2010

In an iPhone application where can you store the model (MVC) object and how do you share it between view controllers? There are a number of ways for doing this. I found the easiest way is to define the model object in the application delegate class and use the UIApplication sharedApplication singleton object from any view controller to access the model.

In your application delegate class define the model. Here the model is assumed to be an NSMutableArray object. Declare the model in the application delegate header file and the define it in the application delegate .m file.

@interface MyAppDelegate : NSObject <UIApplicationDelegate> 
	UIWindow *window;
	NSMutableArray *the_model;

@property (nonatomic, retain) NSMutableArray *the_model;

Now you can access this model in any of your view controllers:

MyAppDelegate *appDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
NSMutableArray *model = appDelegate.the_model;