Wednesday, March 23, 2011

Objective C/Xcode 4: Encoding Problem with Localizable.strings files

When compiling your Xcode project and your are using Localization in the Form of Localizable.strings and can happen that your get one of the following Build Errors.

Possible Build Errors

1.
Conversion of string failed. The string is empty. Command /Developer/Library/Xcode/Plug-ins/CoreBuildTasks.xcplugin/Contents/Resources/copystrings failed with exit code 1

2.
CopyStringsFile
...
Localizable.strings:0: error: validation failed: The data couldn’t be read because it has been corrupted.

Causes


These kind of errors can happen if you copy and paste content within Xcode or from external files in your localization files. The consequence is that the encoding of the file changes to for example Western (Mac OS Roman). The Localizable.strings file should be in UTF-16 though.

Solution


1.
Like in the picture below, navigate in Xcode to the Localizable.strings location and open it so that you can see all the languages you are supporting.


2.
Left-click on the language file the causes the build error.

3.
Make sure your Utilities View is showing in Xcode. Activate on the button at mark 1 in Picture below.


4.
In the Utilities View select the File Inspector. (Small Logo that looks like Page)

5.
Under Text Settings change the encoding to UTF-16(Marked as 2 in the picture above). The Drop-Down might be grayed out but you can click on it anyways. Click on "Convert" on the Popup.

That's it your project should now compile again.

Tuesday, March 22, 2011

Objective C/Xcode 4: How to label and internationalize a Round Rect Button (UIButton) programatically

If you only support one language it is easy to go into Interface Builder and set the Label of your Round Rect Button. For localization it is not as easy though.

How to use localization for UILabels


Text Label elements or UILabels can easily be set to a localized String with this command.

@synthesize nameLabel;

...

self.nameLabel.text = NSLocalizedString(@"name.label.translation", @"Comment for the name label.");

How to NOT use localization for UIButtons

Since buttons have different states the label would disappear if you click it and you only set the title like that.
@synthesize myButton;
...
//Wrong
self.myButton.titleLabel = = NSLocalizedString(@"button.label.translation", @"Comment for the button label.");

How to USE localization for UIButtons

The proper way is to assign the localized string to all states of the UIButton.

@synthesize myButton;
...
//Correct
NSString *buttonLabelString = NSLocalizedString(@"button.label.translation", @"Comment for the button label.");
 [self.myButton setTitle:buttonLabelString forState:UIControlStateNormal];
 [self.myButton setTitle:buttonLabelString forState:UIControlStateHighlighted];
 [self.myButton setTitle:buttonLabelString forState:UIControlStateDisabled];
 [self.myButton setTitle:buttonLabelString forState:UIControlStateSelected];

Wednesday, March 9, 2011

iPhone App: HT-SmartViewer Lite now in the AppStore

Its done. My first iPhone App made its way in the AppStore.

Get it for free now!

The App is a Match Viewer and Statistics App for the free Online Soccer Manager Hattrick. We hope to get people to use it and participate in the process to make it a really great, fun and useful Hattrick App.





Languages supporter are right now English, German, French and Spanish. If you want to see it in a different language feel free to contact us.

For feedback, news and more go to the HT-SmartViewer Homepage oder the HT-SmartViewer Forum.

Thursday, February 17, 2011

Objective C: Terminate App when pushing the Home button on iPhone/iPad

To make sure your iPhone or iPad App does not keep running in the background after you used the Home button, this is the way to go. Terminating the app helps saving resources on your device.

1. Open your project in Xcode.


2. Find the Info-iPhone.plist or Info-iPad.plist file.


3. Left-click once on it to see the Key Value pairs.


4. Right-click on one of the entries and select Add Row.


5. As key enter UIApplicationExitsOnSuspend.


6. Right-click on the new row and select Value Type Boolean.


7. Check the value field.


Let me know if you have any trouble.

Wednesday, February 16, 2011

Objective C: alternating background color in UITableViewCell for iPhone Apps

In one of my iPhone Apps that has a UITableView I wanted to make the background color of the UITableViewCells alternating. Having two different colors in the background of the cells help to improve the readability.


As you can see in the screenshot the odd cells are grey and the even cells are white.
The changes need to be done in the DataSource method cellForRowAtIndexPath.

- (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
 UITableViewCell *cell = [tv dequeueReusableCellWithIdentifier:@"cell"];
 if( nil == cell ) { 
  cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:@"cell"] autorelease]; 
 }
 Fruits *fruit = [fruits objectAtIndex:indexPath.row]; 
 cell.textLabel.text = fruit.fruitName; 
 
        //start of important code for background color changes
        cell.textLabel.backgroundColor = [UIColor clearColor];
 
 UIView *bgColor = [cell viewWithTag:100];
 if (!bgColor) {
  CGRect frame = CGRectMake(0, 0, 320, 44);
  bgColor = [[UIView alloc] initWithFrame:frame];
  bgColor.tag = 100; //tag id to access the view later
  [cell addSubview:bgColor];
  [cell sendSubviewToBack:bgColor];
  [bgColor release];
 }
 
 if (indexPath.row % 2 == 0){
  bgColor.backgroundColor = [UIColor colorWithRed:233.0/255.0
                green:233.0/255.0
                blue:233.0/255.0
                alpha:1.0];
 } else {
  bgColor.backgroundColor = [UIColor clearColor];
 }
 //end of important code

 return cell;
} 

Above is the whole method with all the additional code you need to get a white/grey background color alternation.

Lets go through the main changes in detail:

Make sure the cell text has a transparent background

cell.textLabel.backgroundColor = [UIColor clearColor]; 
This line makes sure your cell text has an transparent background, otherwise you end up with a result like in the screenshot below.

Create a view that holds the new background color

UIView *bgColor = [cell viewWithTag:100];
if (!bgColor) {
 CGRect frame = CGRectMake(0, 0, 320, 44);
 bgColor = [[UIView alloc] initWithFrame:frame];
 bgColor.tag = 100; //tag id to access the view later
 [cell addSubview:bgColor];
 [cell sendSubviewToBack:bgColor];
 [bgColor release];
}
First we check if the cell has already a view with tag id 100. If not, create a new view with the size of the cell(standard 320x44). Then the view gets add to the cell and send to the background.
If the view exists we don't need to create it again.

Set the color for odd and even cells

if (indexPath.row % 2 == 0){
 bgColor.backgroundColor = [UIColor colorWithRed:233.0/255.0
        green:233.0/255.0
        blue:233.0/255.0
        alpha:1.0];
} else {
 bgColor.backgroundColor = [UIColor clearColor];
}
If the cell index is even (0, 2, 4, etc.) the background color of the background color view is set to grey. Else it is set to clear (white).
If you want it to be the other way around use:
if (indexPath.row % 2 == 0){
...

Hope that helps. Please let me know if you have any problems or questions.

Monday, February 7, 2011

Objective C: Use Network Activity Indicator in iPhone Apps with GTMHTTPFetcher

The Google Toolbox HTTP Fetcher (GTMHTTPFetcher) allows you to send synchronous and asynchronous HTTP request in iPhone/iPad Apps using Objective C/Xcode.

Pretty common in those Apps is to display the network activity indicator during the request process.

The below instructions should also work for other HTTP libraries, you just need to replace the observer names accordingly.


This is how you can do it. The example tutorial below shows how to add this functionality to the RootViewController, but it could be added to any ViewController.

In the RootViewController.h


// RootViewController.h

#import <UIKit/UIKit.h>

@class GTMHTTPFetcher;

@interface RootViewController : UIViewController <UINavigationControllerDelegate> {

 int networkActivityCounter;
        ...
}

- (void)startFetchingData;
- (void)fetchData:(GTMHTTPFetcher *)fetcher finishedWithData:(NSData *)retrievedData error:(NSError *)error;

@end

Important here is the networkActivityCounter that will later hold the number of requests that are currently running.

In the RootViewController.m


// RootViewController.m

- (void)viewDidLoad{
 //add observer for fetcher start and stop events
 NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
 [nc addObserver:self selector:@selector(incrementNetworkActivity:) name:kGTMHTTPFetcherStartedNotification object:nil];
 [nc addObserver:self selector:@selector(decrementNetworkActivity:) name:kGTMHTTPFetcherStoppedNotification object:nil];
 
 ...
 
}

First add the observers for the fetch start and stop events in the viewDidLoad method.

#pragma mark Network activity

- (void)incrementNetworkActivity:(NSNotification *)notify {
  ++networkActivityCounter;
  if (1 == networkActivityCounter) {
    UIApplication *app = [UIApplication sharedApplication];
    [app setNetworkActivityIndicatorVisible:YES];
  }
}

- (void)decrementNetworkActivity:(NSNotification *)notify {
  --networkActivityCounter;
  if (0 == networkActivityCounter) {
    UIApplication *app = [UIApplication sharedApplication];
    [app setNetworkActivityIndicatorVisible:NO];
  }
}

The increaseNetworkActivity is called when a fetch requested started, when the counter is at 1 the indicator gets displayed. After when the counter gets increased it doesn't need to be activated anymore, its still running.

Each time a fetch request has stopped the activity gets decreased, at 0 activity the indicator gets invisible.

- (void)dealloc {
 //remove the observer
 NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
 [nc removeObserver:self];
 ...
 
 [super dealloc];
}

Don't forget to remove the observer when not needed anymore.

Friday, January 14, 2011

Objective C: Remove certain characters from NSString

Sometimes when you work in Xcode in the Cocoa Framework you want to filter a NSString so that only certain characters are left. That can be numbers or letters or special characters. Following code snippet can do that for you.

//the String with the original text
NSString *unfilteredString = @"The sum of 1 + 2 = 3.";
//initialize a string that will hold the result
NSMutableString *resultString = [NSMutableString stringWithCapacity:unfilteredString.length];
    
NSScanner *scanner = [NSScanner scannerWithString:unfilteredString];
//define the allowed characters, here only numbers from one to three, equal and plus
NSCharacterSet *allowedChars = [NSCharacterSet characterSetWithCharactersInString:@"123+="];
    
while ([scanner isAtEnd] == NO) {
 NSString *buffer;
 if ([scanner scanCharactersFromSet:allowedChars intoString:&buffer]) {
  [resultString appendString:buffer];     
 } else {
  [scanner setScanLocation:([scanner scanLocation] + 1)];
 }
}
//Print out the result String, will be 1+2=3   
NSLog (@"Result: %@", resultString);