Pitfall in using default values in settings bundle

If you are implementing application settings using iPhone’s Application Preferences, then you will want to take note of this pitfall.

Referring to the schema reference for PSTextFieldSpecifier, you would notice that there is a DefaultValue key. You might thought that this key is to return a default value, when the preference is not set.

In terms of code, you might thought that myvalue would return the default value.

NSString *myvalue = [[NSUserDefaults standardUserDefaults] stringForKey:@"mykey"]

But no, that is NOT the case. myvalue will always return nil, until you go to the Application Preferences page. In order to read a default value correctly, you will have to do more.

Refer to AppPrefs Sample Code on how that can be done. The code is copied here for reference.

	NSString *testValue = [[NSUserDefaults standardUserDefaults] stringForKey:kFirstNameKey];
	if (testValue == nil)
	{
		// no default values have been set, create them here based on what's in our Settings bundle info
		NSString *pathStr = [[NSBundle mainBundle] bundlePath];
		NSString *settingsBundlePath = [pathStr stringByAppendingPathComponent:@"Settings.bundle"];
		NSString *finalPath = [settingsBundlePath stringByAppendingPathComponent:@"Root.plist"];
		NSDictionary *settingsDict = [NSDictionary dictionaryWithContentsOfFile:finalPath];
		NSArray *prefSpecifierArray = [settingsDict objectForKey:@"PreferenceSpecifiers"];
 
		NSString *firstNameDefault;
 
		NSDictionary *prefItem;
		for (prefItem in prefSpecifierArray)
		{
			NSString *keyValueStr = [prefItem objectForKey:@"Key"];
			id defaultValue = [prefItem objectForKey:@"DefaultValue"];
 
			if ([keyValueStr isEqualToString:kFirstNameKey])
			{
				firstNameDefault = defaultValue;
			}
			// Handle for other preferences you might have
			// ...
		}
 
		// since no default values have been set (i.e. no preferences file created), create it here		
		NSDictionary *appDefaults = [NSDictionary dictionaryWithObjectsAndKeys:
										firstNameDefault, kFirstNameKey,
										nil];
		[[NSUserDefaults standardUserDefaults] registerDefaults:appDefaults];
		[[NSUserDefaults standardUserDefaults] synchronize];
	}
 
	// we're ready to do, so lastly set the key preference values
	firstName = [[NSUserDefaults standardUserDefaults] stringForKey:kFirstNameKey];

I cut my own Micro SIM

I refuse to pay an extra $20, for a smaller SIM card.

With dignity, I cut my Singtel standard SIM card to fit for my iPhone 4.

diy-micro-sim 

As you can see, it is not hard. Just cut around the metal piece.

Mobile ATM – An Idea for Paypal X Developer Challenge

I was out jogging the other day.

At the end of my run, I wanted to buy a drink, but I soon realized that I have forgotten to bring along cash with me! I have my iPhone with me, but can it pay for my drinks?

I started to think of solutions..

Thinking: If everyone is a mobile ATM, and I could use my phone to transfer money electronically to these mobile ATM, it will be great! As long as they could “dispense” the money, I would not mind paying a commission fee for the service.

Not bad an idea.. Hence I am submitting it for Paypal X Developer Challenge.

Singtel’s Advertisement for Galaxy S is Inaccurate..

On a full page advertisement for Samsung Galaxy S in Straits Times today:

singtel-ad-with-sg-toto-android

I am happy to find SG Toto as one of the app that works for the Android phone.

Great.

But wait, I don’t remember releasing the app for Android..

A New iPhone App – The LOST Whispers

We are proud to announce the release of a new iPhone app – The LOST Whispers

This is the first entertainment app we have created, and a good prank app we believe it is. What you can do with the app is simple.

Whispers-ad

Yup. That’s what the app does – Play creepy whispering sounds and terrify your friends!

For more info about the app, visit whispers.just2us.com, or simply download now.

How to use MapKit

Apple seems to lack a MapKit programming guide. I have to look through the MapKit reference, search on the Internet, and read blog articles in order to do a few simple tasks with MapKit.

I thought it would be great if there is a MapKit programming guide, similar to the Push Notification Service programming guide provided by Apple.

But there isn’t. So I am here writing one for developers who are interested to use MapKit for that few simple tasks. This post contains 8 code snippets for 8 tasks.

 

1. Adding a map view

If you simply want to add a map to your view, simply create a MKMapView object and insert it. That’s our first big step!

- (void)viewDidLoad {
	[super viewDidLoad];
	// Init our map view 
	mapView = [[MKMapView alloc] initWithFrame:self.view.bounds];
	[self.view insertSubview:mapView atIndex:0];
}

 

2. Configuring the map

With a map, you could now configure various aspects by setting the mapView properties. Examples below:

	// Set the map type such as Standard, Satellite, Hybrid
	mapView.mapType = MKMapTypeStandard;
 
	// Config user interactions
	mapView.zoomEnabled = NO;
	mapView.scrollEnabled = YES;
 
	// Set the region and zoom level
	MKCoordinateRegion region;
	MKCoordinateSpan span;
	CLLocationCoordinate2D location;
	location.latitude = 1.302851; // Singapore!
	location.longitude = 103.85523;
	span.latitudeDelta = 0.02;
	span.longitudeDelta = 0.02;
	region.span = span;
	region.center = location;
	// Set to that region with an animated effect
	[mapView setRegion:region animated:TRUE];
	// Lastly, set the MKMapViewDelegate (we will use this later) 
	mapView.delegate = self;

 

3. Showing the user’s location

To show the user’s location on the map, we set this one special property.

	mapView.showsUserLocation = YES;

 

4. Creating custom annotations/landmarks

If you want to display some landmarks, aka annotations, on the map, you will need to create your annotation class that implement the MKAnnotation protocols.

Say you want to display some shops on the map, this is want you would do.

// ShopAnnotation.h
@interface ShopAnnotation : NSObject <mkannotation> {
	Shop *shop; // Assuming this class contains info about a shop
}
// ShopAnnotation.m	
// Required to implement
- (CLLocationCoordinate2D)coordinate {
	CLLocationCoordinate2D theCoordinate;
	theCoordinate.latitude = shop.latitude;
	theCoordinate.longitude = shop.longitude;
	return theCoordinate; 
}
 
// Optional
- (NSString *)title {
    return shop.name;
}
 
// Optional
- (NSString *)subtitle {
    return shop.address;
}

 

5. Adding annotations to the map

To add the annotations to the map, you would create the ShopAnnotation earlier and add them to mapView.

	for (Shop *shop in allMyShops) {
		ShopAnnotation *shopAnnotation = [[[ShopAnnotation alloc] initWithShop:shop] autorelease];
		[mapView addAnnotation:*shopAnnotation ];
	}

 

6. Handling the annotation views

Annotations are not views. After you added your annotations to the map, you would still need to provide its views. The mapView delegate methods will be called to ask for your annotations’ VIEWS. You will need to create the view and return it for mapView to display.

In our example, we create a MKPinAnnotationView, which is a standard pin that you see in Maps app. You could otherwise create your custom view that extends MKAnnotationView.

- (MKAnnotationView *)mapView:(MKMapView *)theMapView viewForAnnotation:(id <mkannotation>)annotation {
	// If it's the user location, just return nil.
	if ([annotation isKindOfClass:[MKUserLocation class]])
		return nil;
	// If it is our ShopAnnotation, we create and return its view
	if ([annotation isKindOfClass:[ShopAnnotation class]]) {
		// try to dequeue an existing pin view first
		static NSString* shopAnnotationIdentifier = @"ShopAnnotationIdentifier";
		MKPinAnnotationView* pinView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:shopAnnotationIdentifier ];
		if (!pinView) {
			// If an existing pin view was not available, create one
			MKPinAnnotationView* customPinView = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:shopAnnotationIdentifier] autorelease];
			customPinView.pinColor = MKPinAnnotationColorRed;
			customPinView.animatesDrop = YES;
			customPinView.canShowCallout = YES;
 
			// add a detail disclosure button to the callout which will open a new view controller page
			UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
			customPinView.rightCalloutAccessoryView = rightButton;
 
			return customPinView;
		} else {
			pinView.annotation = annotation;
		}<strike></strike><strike></strike>
		return pinView;
	}
}

 

7. Selecting a pin

When a user selects a pin and press the UIButtonTypeDetailDisclosure button within the callout, we can present more details about the annotation. Implement another MKMapViewDelegate to handle this.

- (void)mapView:(MKMapView *)_mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control {
	// Handle it, such as showing another view controller
}

 

8. Open Maps app

If want to provide a route from the user location to the selected annotation, you would need the help of iPhone’s Maps app. This means that your app will exit and Maps app will be opened, with you telling Maps the source and destination to route.

You can open Maps with the schema as such.

	NSString *url = [NSString stringWithFormat:@"http://maps.google.com/maps?saddr=%f,%f&amp;daddr=%f,%f";, userLatitude, userLongitude, [shop.latitude floatValue], [shop.longitude floatValue]];
	[[UIApplication sharedApplication] openURL:[NSURL URLWithString:url]];

 

With that, we have come to the end of a few simple tasks with MapKit!

How to highlight code syntax in WordPress

WP-Syntax is the answer.

For example, this is how I highlight an iPhone’s Objective-C code in this post.

- (void)viewDidLoad   
{    
    [super viewDidLoad];    
    NSString *title = [NSString stringWithFormat:@"My %@ syntax", @"AWESOME"];    
    self.title = title;    
}

 
To use WP-Syntax, simply surround the code with <pre lang=”LANGUAGE”> and </pre>, where LANGUAGE is the programming language.

To find out what to use for LANGUAGE, look under supported languages here.

How to resolve force close caused by Market

This is an issue where an application that is opened from Android’s Market might encounter a force close. txeet had the same issue:

txeet force close 

This is due to the application having two launcher components, and Market is confused and therefore not able to launch. Strangely, some phones do not face the same problem.

Though this is a bug on Android side, the application can resolve by simply adding a line in the manifest file.

<activity-alias android:name="com.android.internal.app.ResolverActivity" android:targetActivity=".Main" android:exported="true"/>

SG Blood v2

Just like my other apps that have gone v2, SG Blood is upgrading to v2 too!

SG Blood is an app for blood donor, and was first released in Jan 2009. I didn’t update the app much over the year, partly because it works well and has no bugs, and partly because I have no improvement planned for it.

But today, I am proud to announce a new feature for the app: Checking blood stock level!

blood stock

The feature is kindly provided by donorweb.

Switching to Nexus One

Ok, I once said that I don’t think much of Nexus One.. but Google is generous enough to give me one.. and since I promised, I shall switch to use Nexus One for a week (:

inexus 

And ya, her name is iNexus.

←Older