Translating Objective-C to C# – Part 1 of n

As I mentioned in the previous post, I’m copresenting at JaxDUG in June on iPhone Development using a Windows Azure-hosted REST API. Before last week, I knew little about Objective-C or Cocoa. I still know very little – but I gained a wealth of knowledge by sitting down with my copresenter Mike Glass for about half an hour and he explained some of the concepts for me and it finally clicked. So I’ve spent the past 2 days reading through Programming iOS 5, Second Edition by Matt Neuberg to familiarize myself with the concepts.
While reading, I found that it was helpful to try and equate the concepts to C# equivalents. I figured that it might be helpful to others as well if I put these comparisons into blog form and shared them to the world. Hopefully this will encourage iOS and Mac developers to take a look at Windows Phone and Windows 8 development in C#. As I’m still learning, I’d appreciate any feedback you might have, and definitely let me know if I’ve said something wrong.
I’ll be using the examples in the eBook as the source, in the order they appear (but not using every example, of course).

Enums

In Chapter 1, he shows a common C enum type defined in Cocoa:
typedef enum {
UIStatusBarAnimationNone,
UIStatusBarAnimationFade,
UIStatusBarAnimationSlide,
} UIStatusBarAnimation;
This is easily convertible to a C# enum:
public enum UIStatusBarAnimation
{
    UIStatusBarAnimationNone,
    UIStatusBarAnimationFade,
    UIStatusBarAnimationSlide
}

Structs

Just like enums, the C-style structs are easy to convert to C# structs.
struct CGPoint {
CGFloat x;
CGFloat y;
};
typedef struct CGPoint CGPoint;
And in C#:
public struct CGPoint
{
    public CGFloat x;
    public CGFloat y;
}

Strings

Strings in Objective-C are treated very similarly to C#, in that the resulting type of a string literal is an actual reference-type class instance.
NSString* s = @"Hello, world!";
In C#, there is no @ delimiter for the start of the string, and the pointers are implicitly managed by the runtime, so there’s no need to be explicit with the * identifier. The NSString type is analogous to System.String.
string s = "Hello, world!";

For Each

Objective-C has an equivalent to C#’s foreach statement, using the more concise “for” and “in” keywords:
for (SomeType* oneItem in myCollection) {
// ... statements ....
}
Again, the pointers are implicitly managed, but this is easily done in C# using foreach:
foreach (SomeType oneItem in myCollection)
{
    // ... statements ...
}

Instance vs Static Methods/Messages

In Objective-C, any time you see a statement in square brackets, that is called passing a message to an object, which is roughly equivalent to calling a method in C#. The first part inside the brackets is the object to pass the message to, followed by the “selector” (or method signature) and their parameters. Each parameter follows a colon, which makes the code more readable than C# in some cases.
In the interface definition for a type (more on that later), or in Apple’s documentation, you will see instance methods defined with a minus sign (“-“) and class (or “static” in C#) methods defined with a plus sign (“+”). So the following method is defined as an instance method:
- (NSString *)stringByAppendingString:(NSString *)aString
While this method is defined as a static method:
+ (id)stringWithContentsOfFile:(NSString *)path
           encoding:(NSStringEncoding)enc
           error:(NSError **)error
The C# equivalent signatures would be (replacing types with those found in the .NET BCL):
public string StringByAppendingString(string aString)
{
    // ...
}
public static object StringWithContentsOfFile(string path, Encoding enc, ref Exception error)
{
    // ...
}
More on id vs object later. Notice that a “pointer pointer” to a reference type is roughly equivalent to the “ref” keyword on a parameter. And clearly, there are static BCL equivalents of these methods in String.Concat(string, string) and File.ReadAllText(string, Encoding) wrapped in a try/catch block.
To call an instance method in Objective-C, you use an object instance as the first part inside the square brackets:
NSString* s1 = @"Hello, ";
NSString* s2 = @"World!"
NSString* s3 = [s1 stringByAppendingString: s2];
If the System.String type had a StringByAppendingString method like NSString (rather than the static String.Concat), the previous code would look like this in C#:
string s1 = "Hello, ";
string s2 = "World!";
string s3 = s1.StringByAppendingString(s2);
Just like the s1 instance was specified inside the square brackets to make it an instance method call, you can specify the type name instead to make it a static method call. This is almost exactly like C#, where you use the Type identifier before the dot instead of the instance. Here’s a static method call in Objective-C:
NSString* myPath = // something or other;
NSStringEncoding myEnc = // something or other;
NSError* myError = nil;
NSString* result = [NSString stringWithContentsOfFile: myPath
                             encoding: myEnc
                             error: &myError];
We can create our own .NET version of NSString’s stringWithContentsOfFile as follows:
public static class StringEx
{
    public static string StringWithContentsOfFile(string path, Encoding encoding, ref Exception error)
    {
        try
        {
            return System.IO.File.ReadAllText(path, encoding);
        }
        catch (Exception ex)
        {
            error = ex;
            return null;
        }
    }
}
And now that we have a Cocoa equivalent, we can call it like this:
string myPath = "something or other";
Encoding myEnc = Encoding.UTF8;
Exception myError = null;
string result = StringEx.StringWithContentsOfFile(myPath, encoding: myEnc, error: ref myError);
Also notice that nil in Objective-C is roughly equivalent to null in C#, and that in this example we are giving our code a very Objective-C feel by using named parameters with colons.

Nesting Method Calls

One thing that threw me off when I started looking at Objective-C is following the trail of nested method calls. Since the first part of a method call is what the message is being sent to, you can use the result of a message as the first part of another message call. In Chapter 3 he uses the following example:
NSArray* arr = [[MPMediaQuery albumsQuery] collections];
And he points out that this is equivalent to the following code:
MPMediaQuery* query = [MPMediaQuery albumsQuery];
NSArray* arr = [query collections];
A C# (or any C-style language) developer should be able to easily see that the first version is equivalent to this (although in reality, Array would be replaced with some generic collection):
Array arr = MPMediaQuery.albumsQuery().collections();
Also notice that this is a mix of a static/class and instance method call in both cases, but either example could be made from 2 nested instance method calls without a change in syntax (other than using the instance identifier rather than MPMediaQuery).

Parameter Lists

For methods with a variable number of parameters, Objective-C offers parameter lists, which is equivalent to C#’s params keyword. From the examples in the book, on the NSArray class there is a class (static) method with the following signature:
+ (id)arrayWithObjects:(id)firstObj, ... ;
The … is the syntax for denoting that the method can receive a variable number of arguments. He then uses this method like so:
NSArray* pep = [NSArray arrayWithObjects:@"Manny", @"Moe", @"Jack", nil];
He points out in the book that the nil terminator is required, and you will get a compiler warning if you forget it. In C#, the NSArray method is equivalent to the following method:
public static Array ArrayWithObjects(params object[] objects)
{
    return objects;
}
Since the C# compiler automatically converts variable length arguments into an array instance, this method has a trivial implementation. It can then be called like so (from within the same type), and a nil terminator is not required:
Array pep = ArrayWithObjects("Manny", "Moe", "Jack");

ID vs Object

This one is a bit tricky. Objective-C has an id keyword which can be used instead of a type identifier to declare a variable or parameter as accepting a pointer to any type of object ever. In C#, you might think this would be equivalent to declaring a variable of the object type. However, my CoWork Jax coworker Mike Glass pointed out that Cocoa also has an equivalent of System.Object, which is NSObject – and all classes that inherit the default allocation and initialization behavior of objects should inherit from it. So if declaring a variable of type System.Object in C# is equivalent to declaring a variable of type NSObject in Objective-C, then what is the .NET equivalent of declaring a variable as id?
It seems to me like there is no direct equivalent. On one hand, id allows you to send messages to that instance that are checked at runtime rather than compile time. So the following code is not statically checked by the compiler, and may crash at runtime:
NSString* s = @"Hello, world!";
id unknown = s;
[unknown rockTheCasbah];
In that sense, you can see where id is not like System.Object, because trying to call rockTheCasbah on a System.Object variable would definitely throw a compiler error. So that makes id behave much like C# 4’s dynamic keyword – it can contain a reference to any object, and method calls at runtime are not statically checked by the compiler.
However, id in Objective-C also behaves much like the IntPtr type which in .NET refers to an unmanaged memory pointer. I would chalk this up to the difference between Objective-C being an unmanaged language and .NET being a managed language though, and leave the rest of this discussion for one to be had over beers. Bottom line – id seems to be most equivalent to C#’s dynamic keyword (but without the expensive DLR overhead), and NSObject is equivalent to System.Object; but in a true Objective-C to C# conversion you would probably use System.Object for id rather than dynamic.

Blocks

Blocks in Objective-C are very easily translatable to lambda expressions in C#. A Block, just like a lambda expression, is an anonymous method that has a special syntax, can be stored to a variable inside another method or passed as a parameter to another method, has a strongly typed parameter list, and has an implicitly typed return type. Blocks in Objective-C are declared by starting the block with the caret (^) symbol. In the example in the book, it is passed as a parameter to NSArray’s sortedArrayUsingComparator method (the block portion is in bold with a gray background):
NSArray* arr2 = [arr sortedArrayUsingComparator: ^(id obj1, id obj2) {
NSString* s1 = (NSString*) obj1;
NSString* s2 = (NSString*) obj2;
NSString* string1end = [s1 substringFromIndex:[s1 length] - 1];
NSString* string2end = [s2 substringFromIndex:[s2 length] - 1];
return [string1end compare:string2end];
}
];
Compare that to the following lambda expression equivalent, assuming there was an instance or extension method on System.Array called SortedArrayUsingComparator (and the comparator parameter could be the delegate Comparison<object>, which takes 2 object types and returns an int):
Array arr2 = arr.SortedArrayUsingComparator((obj1, obj2) =>
{
    string s1 = (string)obj1;
    string s2 = (string)obj2;
    string string1end = s1.Substring(s1.Length - 1);
    string string2end = s2.Substring(s2.Length - 1);
    return string.Compare(string1end, string2end);
});
This example shows that Blocks and C# lambdas are extremely similar, and have very similar syntax and usage. Note that I’ve used the static string.Compare method rather than NSString’s instance compare method as in the original example. Also, the original example is implicitly returning NSComparisonResult rather than int, but with similar results.

Summary

I hope this shows how you can translate some Objective-C to and from C#. I’m still learning this myself, so please give me any feedback you can. Also, make sure you pick up a copy of Programming iOS 5 which these examples came from – it’s an excellent read!
Next time I hope to cover interfaces vs. implementations, type checking, inheritance, alloc-init, polymorphism, self/this and super/base keywords, properties, and initializers from Chapters 4-5.
Previous
Next Post »