Monday, April 27, 2009

General Coding Tips

Avoid the Object.getClass() Method

Avoid using the Object.getClass() method, because it is not efficient and it produces garbage (the Class object) that is never collected. Also avoid using the example.class literal. Behind the scenes, this generates Class.forName(“Example”).

Writing Efficient Loops

You should always factor loop invariant code out of a loop, as in the following example:

    for(int i = 0; i < >
...

}

This code results in vector.size() getting called each time through the loop, which is inefficient. If your container is likely to have more than one element, it is much faster to assign the size to a local variable. In addition, this example using pre-increment (++i) results in smaller code than post-increment (i++). The optimized code appears below:

     int size = vector.size();
for(int i = 0; i < style=""> ...
}

Alternatively, if the order in which you iterate over items is not important, you can iterate backward. Iterating backward avoids the extra local on the stack, and the comparison is also faster, as the following example illustrates:

for(int i = vector.size() - 1; i >= 0; --i) {

...

}



Optimizing Subexpressions

If you ever use the same expression twice, do not rely on the compiler to optimize it for you. Use a local variable, as in the following example:

one(i + 1); two(i + 1); // Avoid
int tmp = i + 1; 
one(tmp); 
two(tmp); // Prefer

Avoid java.util.Enumeration
Avoid using java.util.Enumeration unless you are using it to hide data (in other words, returning an Enumeration of data rather than the data itself). The following example shows a typical use of an Enumeration:

for (Enumeration e = v.elements(); e.hasMoreElements();) {
   o = e.nextElement();
   ...
}

Asking a vector or hash table for an Enumeration object creates unnecessary garbage and is slow. Instead, you can iterate over the elements yourself, as in this example:

for(int i = v.size() - 1; i >=0; --i) {
   o = v.elementAt(i);
   ...
}

If the vector might be modified by another thread, you must synchronize the iteration:

synchronized(v) {
   for(int i = v.size() - 1; i >=0; --i) {
      o = v.elementAt(i);
      ...
   }
}

In Java 2 Platform, Standard Edition (J2SE), you would use an Iterator for this, but Iterators are not available in Java 2 Platform, Micro Edition (J2ME).

Returning null
If you are writing a public method that returns an object, it should never return null unless the following occurs:

  • a null is expected during normal program operation.
  • the javadoc @return parameter states that null is a possible return value.

If a null is not normally expected, then the method should throw an appropriate exception, which forces the caller to deal with the problem explicitly. The caller is not expected to check for a null return value, unless the documentation specifies otherwise.

Passing null into Methods
Do not pass null parameters into an API method unless the API Reference documentation explicitly states that the method supports them.

Passing null into a Constructor
To avoid ambiguity when passing a null into a constructor, you should use this form:

new someObject ((Object)null);

A class can have two or more constructors, such as SomeObject(String) and SomeObject(Object), where passing in a null does not identify which constructor to use. As a result, the compiler reports an error. Not all supported constructors necessarily appear in the API Reference documentation, because some constructors are for internal use only. By casting the null to the appropriate object, you indicate precisely which constructor the compiler should use. This practice also ensures forward compatibility if later releases of the API add new constructors.

Optimizing Division Operations
Division operations are slow on the BlackBerry Wireless Handheld because its processor does not have a hardware divide instruction. When you write code that divides a positive number by two, you should use “shift right by one” instead. The following example illustrates this:

midpoint = width / 2; //avoid this
int = width >> 1; //prefer this

This does not work for negative values. Only use “shift right” (>>) when you know you are dealing with a positive value. It does not work for negative values.

Managing Garbage Collection
Avoid calling System.gc() to perform garbage collection. On a full handheld, this could take two seconds. Let the virtual machine (VM) collect garbage automatically.


Casting Using instanceof
It is more efficient to use instanceof instead of classCastException to evaluate whether a cast succeeds. Here is an example of using a try/catch block to catch the classCastException:

try {
   (String)x.whatever();
} catch(ClassCastException e) {
   // something else
}

Alternatively, you can use instanceof operator:

if(x instanceof String) {
   (String)x.whatever();
} else {
   // something else
}

Using instanceof is faster. The only time you should use the try/catch block is when the failure of the cast is an exceptional circumstance. The BlackBerry Java Development Environment (JDE) compiler and the VM are optimized to perform only one class check in the first block of code. This is true of any code in which the cast is run immediately following a branch determined by an instanceof check. Always perform the cast immediately after the branch so that the optimization can be performed.

Using Longs for Unique Identifiers
You should use longs rather than strings for unique constants, such as globally unique identifiers (GUIDs), hash table keys, and state/context identifiers. So that unique identifiers remain unique across all third-party application developers, you should use randomly generated keys based on a hash of some string. In the input string, you should include enough information to make it unique.

Memory Management tip

Dealing with memory on the iPhone is one of the most difficult
challenges that you will face as a new iPhone developer. Today,
I am going to show you a very simple tip that will help you
debug the memory problems that you are like to face.

One thing that you have to worry about with memory management is
the "retain count" of an object. The retain count is how the
system keeps track of the memory used by an object. If an
object's retain count is zero and your attempt to access it
your app will crash; if you do not make sure the retain
count of your object is 0 when the object goes out of focus you
will have a memory leak.

Clearly, it is important to be able to find out what the current
retain count of an object is. Here is how you can do this:

NSLog([NSString stringWithFormat:@"Retain Count:%i", [someObject retainCount]]);
This writes out the current retain count to the log. The
important function is [someObject retainCount].

Friday, April 24, 2009

Strings in iPhone

The iPhone uses a special class called "NSString" to handle strings. Here is an example of a common use of NSString.
NSString *myString = @"This is my string";
You can use an NSString object in the alert that you learned about last week. Here is how you would use the NSString object "myString" in an alert:
NSString *myString = @"This is my string";

UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"UIAlertView"
message:myString
delegate:self
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alert show];
[alert release];
Notice that the "message" argument of the alert you created above uses the NSString object as an argument. Another thing you will be doing with strings is combining strings to make new ones.
For instance, if I had two strings - a first and a last name - and I wanted to create a new string for a full name I could do something like this:
NSString *firstName = @"Matt";
NSString *lastName = @"Campbell";
NSString *fullName = [NSString stringWithFormat:@"My name is %@ %@",
firstName, lastName];

If you were to put fullName into an alert it would say "My name is Matt Campbell". How the stringWithFormat function works is that you give it a string with special symbols in it. The function will replace the symbols with the strings in give it as the next arguments to the function.
Note that when you are using the alert object you need to follow the "alloc, use, release" pattern while the NSString only requires you to use the function after which you may safely forget about it.
This has something to do with the memory management features of the iPhone. Essentially, when you use an object's "alloc" you need to "release" at some point in the future. NSString does not use an alloc in this instance so it does not need to be released while UIAlert does. More details about memory management will be discussed in this mailing list in the future.

Alert box in iPhone

An alert box is a quick way to communicate to your users. Alert boxes look like a rounded square with a message and a button on it. You may put this code into your project to get an alert box:
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"UIAlertView"
message:@"Hi There!" delegate:self
cancelButtonTitle:@"OK"
otherButtonTitles: nil];

[alert show];
[alert release];

As you can see from the code above, square brackets are the order of the day in Objective-C, the iPhone programming language. For now, note that text that comes right after the word "message:". This is where you control what the alert box presents to the user.
Finally, notice the overall pattern of using objects in Objective-C: alloc, "do stuff", release. This is something that you will be using often in your iPhone programming.

Looping in Objective-C

Looping in Objective-C

Loops are the gears of programming: it is what makes the code take action.  The two loops I use most often is the for loop (to do a predefined number of steps) and what is usually called a foreach loop (to move though a list of objects).

//This loop simply repeats an action
//a set amount of times:
for (int i=0; i<=3; i++)
    NSLog([NSString stringWithFormat:@"i=%i", i]);
  
//Create an array of strings for the next example:
NSMutableArray *bunchOfThings = [[NSMutableArray alloc] init];
[bunchOfThings addObject:@"Zero"];
[bunchOfThings addObject:@"One"];
[bunchOfThings addObject:@"Two"];
[bunchOfThings addObject:@"Three"];
  
//This is sometimes called a "for each" loop
//Using this list will repeat actions for each
//object in a list.
//Hint: you can use this for any type of list of
//objects so if you have list of custom defined
//objects this is an easy way to work with them all
//at one time.
for(NSString *s in bunchOfThings)
    NSLog([NSString stringWithFormat:@"s=%@", s]);
  
//The array must be released since it was alloc/init earlier.
[bunchOfThings release];


That is it!