Archive for December, 2009

28 DecAlternative to checking a debug state “#ifdef DEBUG” via precompiler’s defines

There is a nice post about “#ifdef DEBUG” approach, e.g. to turn NSLog on/off when debuggin/releasing.

I want to add own 5 cents. Quite often we need to know if currently running system is a real device or the simulator. I was need that in Vipassana app (iTunes link) - a small meditation helper for my friend. It’s thrown when you try to detect a silent mode on the simulator. That’s why we need to set a check:

#ifdef __i386__ NSLog(@"SOUND TEST PAST");#else    [self ifSilentModeThenMessage];#endif

Surely it works with any current iPhone models and Macs with i386 architecture.

25 DecWhy Open Feint 2.4 rocks

One more good news this week. Open Feint gives us “A Special Holiday Present to You: Version 2.4 and the new Players Website!”

The most expected feature were:

  • A simplified UI focused on ease of use, it had a hard navigation and dark colors before
  • Brand new cross-promotional tools. I didn’t look what does mean, but cross promotional is very important thing
  • Geo-location Leaderboards. FINALLY! We had this feature 5 months ago before decide to switch to OF. Users love to know others play not far





I could wait no more minute to try Geolocation Leaderboards and embed new version in current Road Slot 1.4 beta.



That how it looks on the simulator:

It shows just me now because it’s not published version.Anyway it’s quite interesting, see what it will transform into over time.

UPD:
Played a little with new version we found several small bugs and it’s thrown several times. The easy bug is this code does work but not silently:

[OFHighScoreService setHighScore:currentScore        forLeaderboard:leaderboard        silently:YES          onSuccess:OFDelegate(nil, nil)          onFailure:OFDelegate(nil, nil)];

Small research and the problem is solved. Look this method in “OFHighScoreService.mm”

+ (void) setHighScore:(int64_t)score withDisplayText:(NSString*)displayText forLeaderboard:(NSString*)leaderboardId silently:(BOOL)silently onSuccess:(const OFDelegate&)onSuccess onFailure:(const OFDelegate&)onFailure{ [OFHighScoreService setHighScore:score withDisplayText:displayText withCustomData:nil forLeaderboard:leaderboardId silently:NO onSuccess:onSuccess onFailure:onFailure];} // >>>>> + (void) setHighScore:(int64_t)score withDisplayText:(NSString*)displayText forLeaderboard:(NSString*)leaderboardId silently:(BOOL)silently onSuccess:(const OFDelegate&)onSuccess onFailure:(const OFDelegate&)onFailure{ [OFHighScoreService setHighScore:score withDisplayText:displayText withCustomData:nil forLeaderboard:leaderboardId silently:silently onSuccess:onSuccess onFailure:onFailure];}

The second is updated right way.

25 DecRouteMe is alternative map control to Google Maps from iPhone SDK

A little bit tired cause limitations of built-in Google Maps control. It’s good chance to write some samples of using alternatives.

Theory

There are two alternative map controls I was working with:
  1. Route me
    1. BSD licensed open source. It’s up to you if it’s an advantage
    2. Support lots of sources: OpenStreetMap, Microsoft Virtual Earth, Cloud Made and even old school Yahoo Maps and some other less popular
    3. Formed discussing community – Google Group
  2. Cloud Made
    1. Piece of larger project, so officially has support team and potentially better integration with Cloud Made maps
    2. I use it at very early stage, so not sure of current quality
    3. Has tons of cool themes for maps
It’s enough of facts and theory, time for practice. As a first task let’s embed maps and give user to select the maps source. I prefer Route Me because it can show Cloud Made maps also.

Practice preparations

  1. Open xCode and create new project. I chose View-Based Application and named “RouteMeSourceSelection”.
  2. Download actual Route Me sources
  3. Setup Route Me control very accurately step by step with the Embedding Guide
Now you must have buildable project to continue. If you have some problems feel free to download the sample sources for comparing.

Add Route Me Control (code)

Open UIViewController header file (mine is “RouteMeSourceSelectionViewController.h”) and:

  1. #import “RMMapView.h”
  2. add protocol “RMMapViewDelegate”
  3. create IBOutlet RMMapView *mapView;
Open UIViewController source file and override “- (void)viewDidLoad” method:
- (void)viewDidLoad {    [super viewDidLoad][RMMapView class]; // this important, maps won't display without it [mapView setDelegate:self];}

Add Route Me Control (design)
  1. Open your .xib file in Interface Builder (IB)
  2. Add subview to existing one and set its class to RMMapView
  3. Set IBOutlet of an UIViewController to the just added RMMapView

Now run the project and you will see the maps with default Open Street View source.

All that were really easy. Now give a user possibility to select map source from UIPickerView.

Map source UIPickerView (code)

Open the controller header file and add protocols UIPickerViewDelegate and UIPickerViewDataSource, then add and several IBOutlets:

#import #import "RMMapView.h" @interface RouteMeSourceSelectionViewController : UIViewController<rmmapviewdelegate, uipickerviewdatasource="" uipickerviewdelegate,="">{ IBOutlet RMMapView *mapView; IBOutlet UIPickerView *mapSourcePicker; IBOutlet UIBarButtonItem *mapSettingsBarButton;} - (IBAction) showMapsSettings; @end
Now we should implement necessary methods for UIPickerView to let it show a list of available map sources to select:
static NSArray *titles = nil- (NSString *)pickerView:(UIPickerView *)pickerView     titleForRow:(NSInteger)row    forComponent:(NSInteger)component{ return [titles objectAtIndex:row];} - (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component{ if (!titles) {  titles = [[NSArray alloc] initWithObjects:      @"Open Street Maps",       @"Yahoo Map",      @"Virtual Earth Aerial",       @"Virtual Earth Hybrid",       @"Virtual Earth Road",       @"Cloud Made Map",       nil]; }  return [titles count];} - (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView{ return 1;}

Make showMapsSettings method to show/hude the UIPickerView and set some UI trifles:

- (IBAction) showMapsSettings{ BOOL toShow = [mapSourcePicker isHidden]if (toShow) {  [mapSettingsBarButton setStyle:UIBarButtonItemStyleDone]; } else // hidding {  [mapSettingsBarButton setStyle:UIBarButtonItemStyleBordered];  [self setMapSourceWithNumber:[mapSourcePicker selectedRowInComponent:0]]; }  [mapSourcePicker setHidden:![mapSourcePicker isHidden]]; [mapView setUserInteractionEnabled:[mapSourcePicker isHidden]];}

And the main part is to change map source of the mapView object:

#import "RMVirtualEarthSource.h"#import "RMYahooMapSource.h"#import "RMCloudMadeMapSource.h"#import "RMOpenStreetMapsSource.h" #define CONST_MAP_KEY_bing @""#define CONST_MAP_KEY_cloud @"" - (void) setMapSourceWithNumber:(int)number{ if (mapSourceNumber == number)  returnswitch (number) {  case 0:   mapView.contents.tileSource = [[RMOpenStreetMapsSource alloc] init];   break;  case 1:   mapView.contents.tileSource = [[RMYahooMapSource alloc] init];    breakcase 2:   mapView.contents.tileSource = [[RMVirtualEarthSource alloc] initWithAerialThemeUsingAccessKey:CONST_MAP_KEY_bing];    break;  case 3:   mapView.contents.tileSource = [[RMVirtualEarthSource alloc] initWithHybridThemeUsingAccessKey:CONST_MAP_KEY_bing];    break;  case 4:   mapView.contents.tileSource = [[RMVirtualEarthSource alloc] initWithRoadThemeUsingAccessKey:CONST_MAP_KEY_bing];    breakcase 5:   mapView.contents.tileSource = [[RMCloudMadeMapSource alloc] initWithAccessKey:CONST_MAP_KEY_cloud styleNumber:1];   breakdefault:   return;   break; }  // this trick refreshs maps with new source [mapView moveBy:CGSizeMake(640,960)];  [mapView moveBy:CGSizeMake(-640,-960)];  mapSourceNumber = number; // remember user choice between runnings [[NSUserDefaults standardUserDefaults] setInteger:mapSourceNumber forKey:@"mapSourceNumber"];}

To obtain developer API key for Cloud Made and Virtual Earth (Bing) you need to register and submit a form:

The last thing I want to add is to remember what user chose during last app using. Let’s modify a viewDidLoad to:

- (void)viewDidLoad {    [super viewDidLoad][RMMapView class]; [mapView setDelegate:self]int number = [[NSUserDefaults standardUserDefaults] integerForKey:@"mapSourceNumber"]; [self setMapSourceWithNumber:number]; [mapSourcePicker selectRow:mapSourceNumber inComponent:0 animated:NO];} 

Note, selected map source number is stored to standartUserDefaults at end of setMapSourceWithNumber.

Map source UIPickerView (design)

Open IB to add:

  1. UIToolbar with one UIBarButtonItem connected to its IBOutlet
  2. connect an UIBarButtonItem press event with showMapsSettings IBAction
  3. UIPickerView above the map view and set it hidden 
  4. then connect an UIPickerView with IBOutlet and set its delegate and dataSource to the file’s owner

If you did all right and I did not forget something to describe you should have working app. Please run you application and campare to mine:

This sample is a part of my real application - Meeting Point. It’s free to download, try it.

24 DecTwo news: bad and good

Bad news is that iTunes Connect site is closed for holidays and will reopen on December 28. It’d be a good one, unless I want to change some art and submit an update of GPS Speed. It’s downloaded more than a thousand times a day. It’s quite amusing because the app is not unique and has another ten competitors in the top. Time will show.

And in general I currenlty don’t need to rest, petient work is a best work often.

The second news is that I’ve looked updated sample package of iPhone 3.0 Cookbook by Erica Sadun. It’s amazing. There are so much good samples that I think about stop to post code snippets on the blog. Erica Sadun made exhaustive answer to many answers. It could be used not only by begginers, but expirienced user can find short and interesting solutions there.

Please use that, I insist: http://github.com/erica/iphone-3.0-cookbook- 

15 DecTime for Technorati

Just want to look how many people find the blog interesting.
http://technorati.com/blogs/iphone-dev-tips.alterplay.com

11 DecUsername and Password UITextFields in UIAlertView prompt

Today I will show how to transform an UIAlertView to a prompt of username and password textfields. Actually it’s quite easy for expert of adding subviews or creating own custom controls. So current code snippet is destined for begginers.

I propose to do it in next succession:

  1. Initilize standard UIAlertView. There is a trick here. We need to set a message body to @”nnn”, it makes a shift and create a place for the text fields.
  2. Create two UITextField and initialize them with specific frames. Then add them as subviews to the UIAlertView. Don’t forget to customize a background color, placeholders, securityText property. 
  3. Lastly show UIAlertView with a little shift to top and set first UITextField as a FirstResponder if necessary.
The source code:

UITextField *textField; UITextField *textField2;

 UIAlertView *prompt = [[UIAlertView alloc] initWithTitle:@"Username and password"               message:@"nnn" // IMPORTANT             delegate:nil              cancelButtonTitle:@"Cancel"              otherButtonTitles:@"Enter", nil];

 textField = [[UITextField alloc] initWithFrame:CGRectMake(12.0, 50.0, 260.0, 25.0)];  [textField setBackgroundColor:[UIColor whiteColor]]; [textField setPlaceholder:@"username"]; [prompt addSubview:textField];

 textField2 = [[UITextField alloc] initWithFrame:CGRectMake(12.0, 85.0, 260.0, 25.0)];  [textField2 setBackgroundColor:[UIColor whiteColor]]; [textField2 setPlaceholder:@"password"]; [textField2 setSecureTextEntry:YES]; [prompt addSubview:textField2];

 // set place [prompt setTransform:CGAffineTransformMakeTranslation(0.0, 110.0)]; [prompt show];    [prompt release];

 // set cursor and show keyboard [textField becomeFirstResponder];

11 DecThe shortest way to play sound effect on iPhone [code snippet]

  1. Define static SystemSoundID for sound effect
  2. Initilize this SystemSoundID
  3. Call our static method which plays sound effect: AudioServicesPlaySystemSound
static SystemSoundID soundFileObjectClick;
- (void)applicationDidFinishLaunching:(UIApplication *)application {
 CFURLRef soundFileURLRefClick  = CFBundleCopyResourceURL (CFBundleGetMainBundle (), CFSTR ("button-30"), CFSTR ("wav"), NULL);
 AudioServicesCreateSystemSoundID (soundFileURLRefClick, &soundFileObjectClick);
}
+ (void) clickSoundEffect{
 AudioServicesPlaySystemSound (soundFileObjectClick);
}

Please learn:

07 DeciPhone silent mode detection

Updating friend’s meditation utility there was a necessary to alert user if his device in silent mode. Silent mode is vibration on.

That’s a short snippet:

#import "AudioToolbox/AudioToolbox.h"

- (void) ifSilentModeThenMessage{ CFStringRef state; UInt32 propertySize = sizeof(CFStringRef); AudioSessionInitialize(NULL, NULL, NULL, NULL); AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &propertySize, &state);

 if(CFStringGetLength(state) == 0) {   UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Silent mode"               message:@"Please turn sound on"                delegate:self cancelButtonTitle:@"Ok"              otherButtonTitles:nil];  [alert show];  [alert release]; }}