Objective-C in eyes of .NET developer

Objective-C in the eyes of the C# developer

We have all used or at least heard of Apple’s iOS and its famous Objective-C language that is to be replaced by Swift but still is strong and thriving.

But only few of us except native iOS developers community had a chance to play with it and be able to compare it in practical way.

This article is a unique opportunity for you C# (or JAVA) developer to read about the Objective-C in the eyes of the C# Developer.

So, without further ado let’s jump in right into the differences between C# and Objective-C.

Concepts differences in Objective-C vs C#

Protocols

Objective-C allows you to define protocols, which declare methods expected to is use for a particular situation. Protocols implement in the classes conforming to the protocol.

A simple example would be a network URL handling class; it will have a protocol with methods like processCompleted delegate method that intimates the calling class once the network URL fetching operation is over.

A syntax of protocol is show below.

@protocol ProtocolName@required// list of required methods@optional// list of optional methods@end

The methods under keyword @required must be implemented in the classes that conforms to the protocol and the methods under @optional keyword are optional to implement.

Here is the syntax for class conforming to protocol

@interface MyClass : NSObject <MyProtocol>...@end

This means that any instance of MyClass will respond not only to the methods declared specifically in the interface, but that MyClass also provides implementations for the required methods in MyProtocol. There is no need to declare the protocol methods in the class interface – the adoption of the protocol is sufficient.

Memory management

In .NET world, we have a beast named Garbage Collector responsible for memory management. However, how to solve it in Objective-C?

In early days of Objective-C and iOS developers was responsible for memory management but in 2013 something change.

Automatic Reference Counting (ARC) is a compiler feature that provides automatic memory management of Objective-C objects.

You no longer need to remember about usage of retain, release and autorelease, ARC automatically inserts appropriate memory management calls for you at compile time. The compiler also generates appropriate dealloc methods for you.

ARC Enforces New Rules

To work, ARC imposes some new rules that are not present when using other compiler modes. The rules are intended to provide a fully reliable memory management model; in some cases, they simply enforce best practice, in some others, they simplify your code or are obvious corollaries of your not having to deal with memory management. If you violate these rules, you get an immediate compile-time error, not a subtle bug that may become apparent at runtime.

  • You cannot explicitly invoke dealloc, or implement or invoke retain, release, retainCount, or autorelease.
    The prohibition extends to using @selector(retain), @selector(release), and so on.
    You may implement a dealloc method if you need to manage resources other than releasing instance variables. You do not have to (indeed you cannot) release instance variables, but you may need to invoke [systemClassInstance setDelegate:nil] on system classes and other code that is not compiled using ARC.
    Custom dealloc methods in ARC do not require a call to [super dealloc] (it actually results in a compiler error). The chaining to super is automatic and enforce by the compiler.
    You can still use CFRetain, CFRelease, and other related functions with Core Foundation-style objects (see Managing Toll-Free Bridging).
  • You cannot use NSAllocateObject or NSDeallocateObject.
    You create objects using alloc; the runtime takes care of deallocating objects.
  • You cannot use object pointers in C structures.
    Rather than using a struct, you can create an Objective-C class to manage the data instead.
  • There is no casual casting between id and void *.
    You must use special casts that tell the compiler about object lifetime. You need to do this to cast between Objective-C objects and Core Foundation types that you pass as function arguments. For more details, see Managing Toll-Free Bridging.
  • You cannot use NSAutoreleasePool
    ARC provides @autoreleasepool blocks instead. These have an advantage of being more efficient than NSAutoreleasePool.
  • You cannot use memory zones.
    There is no need to use NSZone any more—they are ignore by the modern Objective-C runtime anyway.

To allow interoperation with manual retain-release code, ARC imposes a constraint on method naming:

  • You cannot give an accessor a name that begins with new. This in turn means that you can’t, for example, declare a property whose name begins with new unless you specify a different getter:

But I want to disable ARC

Use Compiler Flags to Enable and Disable ARC

You enable ARC using a new -fobjc-arc compiler flag. You can also choose to use ARC on a per-file basis if it is more convenient for you to use manual reference counting for some files. For projects that employ ARC as the default approach, you can disable ARC for a specific file using a new -fno-objc-arc compiler flag for that file.

ARC is supported in Xcode 4.2 and later OS X v10.6 and later (64-bit applications) and for iOS 4 and later. Weak references are not supported in OS X v10.6 and iOS 4. There is no ARC support in Xcode 4.1 and earlier.

Swift memory management?

Swift uses ARC out of the box. In most cases, this means that memory management “just works” in Swift, and you do not need to think about memory management yourself. ARC automatically frees up the memory used by class instances when those instances are no longer needed.

I need to deal with legacy code.

Read Advanced Memory Management Programming Guide.

Objective-C language syntax differences

Language syntax has many differences than C# or even VB.NET below you could find short summary how to achieve most common usages. However, Objective-C have also many common syntaxes.

Below you could find some common code samples.

Variables

C#

string name = "Maciej";
int score = 1;
double income = 124.00;
bool isDone = false;
DateTime today = DateTime.Now

Objective-C

NSString *name = @"Maciej";
int score = 1;
double income = 124.00;
BOOL isDone = NO;
NSDate *today = [[NSDate alloc] init];

Arrays

C#

string[] brands = { "Ford", "Porsche", "Honda" };

Objective-C

NSArray *brands = @["Ford", "Porsche", "Honda"];
NSMutableArray *brands = @["Ford", "Porsche", "Honda", nil];

However, what is the difference between NSArray and NSMutableArray? Simply every object with Mutable in name can be modify during runtime. NSArray object needs to be recreated.

In Objective-C, we also have different types of “arrays” like NSSet or NSDictionary.

Statements

C#

string result = score == 1 ? "Great" : "Not so great";
if(score == 1)
{
result = "Great";
}
else
{
result = "Not so great";
}

Objective-C

NSString *result = score == 1 ? @"Great" : @"Not so great";
if(score == 1) {
result = @"Great";
}
else {
result = @"Not so great":
}

Exceptions

If we want, throw an exception from our method we can simply use instance of NSError. We can also create our own exception objection and inherit from NSError.

Working with objects

When we create software, we deal with many objects. Objective-C is object-oriented language with allow us to create our own classes.

Main difference between C# and Objective-C is that this last one requires creation of interface first.

Interface

@interface TodoItem : NSObject
@property NSString *title;
@property NSDate *dueDate;
@property BOOL *isDone;
- (void) setTaskAsDone;
- (BOOL) checkIfTitleIsValid:(NSString*)value;
- (BOOL) checkIfTitleAndDueDateAreValid:(NSString*)value secondValue:(NSDate*) date;
@end

Implementation

@implementation TodoItem
- (void) setTaskAsDone {
NSLog(@"Task is done");
}
- (BOOL) checkIfTitleIsValid:(NSString *)value {
BOOL status = true;
NSLog(@"Value to validate %@", value);
return status;
}
- (BOOL) checkIfTitleAndDueDateAreValid:(NSString *)value secondValue:(NSDate *)date {
BOOL status = NO;
NSLog(@"Values to validate %@; %@", value, date);
return status;
}
@end

Here we have a definition of simple class with a few methods. How to create an instance of object now? Below is the answer use square brackets and keyword alloc followed by init keyword.

TodoItem *newTodo = [[TodoItem alloc] init];
newTodo.title = @"Buy some milk";
NSLog(@"Create new todo with title %@", newTodo.title);
[newTodo setTaskAsDone];

Inheritance

Objects can inherit from others and extend the functionality. How to do that in Objective-C. It is quite simple as use of keyword super.

@interface Vechicle : NSObject
@property NSString *make;
@property NSString *model;
- (void) drive:(int) distance;
@end
@implementation Vechicle
- (void) drive:(int)distance {
NSLog(@"Vechicle start driving at distance %d", distance);
}
@end
@interface Car : Vechicle
@property int numberOfDoors;
@end
@implementation Car
- (id) initWithMakeAndModel:(NSString *)make model:(NSString *)model {
self = [super init];
if(self) {
self.make = make;
self.model = model;
}
return self;
}
- (void) drive:(int)distance {
NSLog(@"Car start driving at distance %d", distance);
}
@end

.h and .m files, why we need them?

They are used to separate between the public and private parts of the class. The .h file is a header file for public declarations of your class like an API, while the .m file is the private implementation.

When you need to call a function at the other files, just need to import the .h files for referencing. For example,

#import <Foundation/Foundation.h>

In the .h file, we can declare public @property of the class, which can be called from outside:

@property (strong, nonatomic) NSString *something;

Here the @property is a pointer to an object whose class is NSString. All objects live in the heap, thus we need the *. As a side note, the strong means “keep the object points to in memory until I set this property to nil”. Nonatomic means “access to this property is not thread-safe”, otherwise the compiler will generate locking code.

NSObject core of everything

This class is the root class of most Objective-C class hierarchies, from which subclasses inherit a basic interface to the runtime system and the ability to behave as Objective-C objects. (source).

Summary

Is it different or similar, do you like it or despise it – decide for yourself.
Either way it’s good to know what it is from the programmer perspective and we hope we’ve just help you with that.

Here, at Altkom Software and Consulting you have a access to unique approach to development of your skills, not only in your main area of competence but also to take a peek outside your box.

Maciej Gos
Team Lead