“If the only language you know is Java or C #, I don’t think you are a professional programmer — you are like a young carpenter who has worked with only one kind of tree so far.”
Uncle bobA few months ago, I started developing applications for the iPhone. Switching from .NET and C # to Cocoa and Objective-C was not without incident, but it was quite interesting and informative. Soon I have to help develop the new platform and other developers of our company. Therefore, I decided to write a series of introductory notes, which I hope will make this transition smoother.
This post will provide a small set of facts about Objective-C from the point of view of a C # developer.
')
- Objective-C is an object-oriented language, an “honest” extension of C (a program written in C is an Objective-C program, which is not always true, for example, for C ++).
Enough detail about the language was written in a recent Objective-C article from scratch . - Two files are created to describe the object - the header file with the .h extension and the implementation file with the .m extension.
- Objective-C classes are objects; roughly speaking, an Objective-C class can be thought of as implementing a factory method pattern with a set of static methods.
- multiple inheritance, as well as in C #, is not supported.
- NSObject is the “equivalent” of the base System.Object class in .NET.
- when we write an interface in Objective-C, consider the class C #.
- and what in C # we call interface, in Objective-C we call protocol.
- In Objective-C, there are two types of methods - class methods (we start their declaration with a "+" sign) and instance methods (the declaration begins with a "-"). Class methods, as you understand, are the same static C # methods.
- if we want to call the object's method, we send it a message about it (Objective-C is a message-oriented language, unlike function-oriented C #).
- in Objective-C, all methods are public (more precisely, there is generally no separation of methods according to access levels).
- in Objective-C, all methods are virtual (that is, any method can be redefined in a derived class).
- Unfortunately, there is no garbage collector in Objective-C (when programming for the iPhone). Instead, a reference counting mechanism is used.
- To get the property we are used to, we use the @property keyword to declare properties in the header file, and in the implementation file we generate a getter and a setter using @syntesize.
- #import is using
- self is a this pointer
- super is base
- id is like object
Message sending
In general, the approach of sending messages in Objective-C and, as a result, the method of naming methods is a whole philosophy. At Habré, there was already a post that
when people see Objective-C methods, people lose their eyes . This article is intended for people trying to shove them back. The easiest way to do this is to see the analogy with something familiar.
Let's see what a method call looks like in Objective-C. In each example, there will be a real equivalent in C #.
Method without parameters:
C #:
someString. ToLower ( ) ;
Objective-C:
[ someString ToLower ] ;
With one parameter:
someString. Equals ( anotherString ) ;
[ someString isEqualToString : anotherString ] ;
With several options:
someString. EndsWith ( anotherString, true , someCulture ) ;
[ someString isEndedWithString : anotherString withIgnoreCase : YES andCultureInfo : someCulture ] ;
Attached messages:
someString. Substring ( 1 ) . EndsWith ( anotherString. Trim ( ) , true , CultureInfo. CurrentCulture ) ;
[ [ someString getSubstringStartedAtIndex : 1 ] isEndedWith : [ anotherString Trim ] withIgnoreCase : YES andCultureInfo : [ CultureInfo getCurrentCulture ] ] ;
As it was written above, in Objective-C two types of methods are instance methods and class methods. Let's see how they are declared in C # and Objective-C.
Instance method:
public int sum ( int firstNumber, int secondNumber ) ;
- ( int ) sumOfFirstNumber : ( int ) firstNumber andSecondNumber : ( int ) secondNumber;
Class method (or static method in C #):
static int Length ( string str ) ;
+ ( int ) Length : ( NSString * ) str;
A bit about designers and destructors
As in C #, we can create an object using the new keyword.
[ someObject new ] ;
This method is similar to the following operation.
[ [ someObject alloc ] init ] ;
alloc allocates memory for the object, and init initializes this chunk of memory to some default parameters. In C #, when you call a constructor, these operations are not logically separated.
It is recommended to use the second approach, since it shows more precisely the mechanism for creating an object (and we should understand what we are doing, right?) And supports the possibility of using different initialization options (we can override the constructor).
[ [ someObject alloc ] initWithTitle : @ "SomeTitle" ] ;
Here is an example of declaring several constructors of the NSString class:
- ( id ) init ;
Returns an initialized NSString object that does not contain characters.
- ( id ) initWithString : ( NSString * ) aString ;
Returns an initialized NSString object by copying characters from another NSString object.
- ( id ) initWithCharacters : ( const unichar * ) characters length : ( NSUInteger ) length ;
Returns an initialized NSString object containing the specified number of characters from the given character array.
If init is a constructor in Objective-C (or a bunch of alloc + init), then dealloc is a destructor (freeing memory). As in C #, it is called automatically.
And a little about the reference counter
When transitioning from C #, memory management when developing on Objective-C is one of the most important issues. We (.NET developers) are spoiled in this sense - we are used to the fact that in most cases the garbage collector will do everything for us. Here, this approach will not work, without careful work with the application's memory, you will regularly receive "strange" errors.
The reference counter mechanism implements the base for all NSObject objects. The idea is as follows: each object contains a reference count, if the number of links becomes zero, the destructor (dealloc) is called. Never call dealloc yourself!
The counter value is incremented by one when allocating memory for an object (calling the alloc / new method), when creating a copy of the object (copy message), when sending a retain message to the object. To reduce the counter value by one, you need to send a release message to the object.
The scheme of working with an object is usually this: created (the reference counter increased by one), performed the necessary actions (all interested objects send him retain messages and then release), sent a release message (reduced the counter by one), the destructor is called.
With the release message, you need to be careful and avoid unnecessary calls, since a repeated call to the object's destructor will drop the program.
It is also possible to get rid of the need to remember that you need to send a release message to the object (sometimes this is due to the fact that the object is returned by the method and we do not know its future fate). This can be done using the autoRelease message and the AutoreleasePool object.
[ [ [ someObject alloc ] init ] autorelease ] ;
The object is recorded in the AutoreleasePool. That is, the release message will be sent to the object "sometime later," and until then the object will be in memory. “Sometime later” occurs when a release or drain message is sent to an AutoreleasePool object.
In continuation of the topic I advise you to look at the recent Shivani Khanna
"Objective C for C # Developers" report.
Supplement / corrections are welcome.
Thank you for reading the article!