Le langage Objective-C est un simple langage de programmation conçu pour être un langage orienté objet des plus sophistiqué. L’Objective-C est un dérivé du C ANSI pour la syntaxe de définition des classes, des méthodes et des propriétés, comme tout autres langages qui proposent les mêmes extensions de construction dynamique de classes. La syntaxe et la conception des classes sont basées en grand partie sur Smalltalk, un des premiers langages orientés objets.
Si vous avez déjà programmé avec un langage orienté objet, les informations suivantes devraient vous aider à apprendre la syntaxe de base de l’Objective-C. La plus part des concepts traditionnels des langages objets, comme l’encapsulation, l’héritage et le polymorphisme, sont présents dans l’objective-C. Il y a quand même quelques différences importantes, mais ces différences ne sont pas détaillées dans cet article et sont disponibles si vous en avez besoin.
Si vous n’avez jamais programmé en utilisant un langage objet, vous avez besoin de comprendre au moins la base des concepts objets avant de pouvoir aller plus loin. L’utilisation des objets et des constructions orientées objets sont fondamentales pour la conception d’application pour l’Iphone, et comprendre comment les objets inter-agissent entre eux est critique pour créer votre application. Pour une approche des concepts orientés objets, lisez “Object-Oriented Programming with Objective-C”. D’autre part, lisez aussi “Cocoa Fundamentals Guide” pour avoir plus d’information sur la conception des modèles orientés objets utilisés dans Cocoa.
Pour une introduction plus détaillée sur L’Objective-C et sa syntaxe, lisez “Objective-C 2.0 Programming Language”.
L’Objective-C est une surcouche de la version ANSI du C et possède la même syntaxe de base. Comme avec un code en C, vous définissez des fichiers headers1) et des fichiers sources pour séparer les déclarations publiques du code. Les fichiers headers utilisent comme une extension de fichier en fonction de leurs utilisations.
Table des extentions de fichiers :
| Extension | Source type |
|---|---|
| .h | Fichier Header qui contient des déclarations de classes, de types, de fonctions, et les déclarations de constantes. |
| .m | Fichier Source. C’est l’extension la plus courante qui peut contenir de l’Objective-C et du C |
| .mm | Fichier Source qui peut contenir du C++ en plus du code Objective-C et du C. Cette extension doit être utilisée si vous faites référence à des classes en C++ ou à votre code en Objective-C. |
Quand vous voulez inclure des fichiers headers dans votre code, vous pouvez utiliser la directive standard du compilateur #include mais l’objective-C a une méthode bien plus efficace. La directive #import est identique à #include, excepté que l’on a l’assurance qu’un ficher n’est pas inclus plus d’une fois. Dans les exemples et la documentation d’Objective-C vous retrouverez plus souvent l’utilisation de la directive #import, votre code devrait en faire de même.
Comme toutes sur-couche au C, l’Objective-C porte les mêmes conventions pour la déclaration des chaines de caractères en C. En d’autres termes, un caractère est entouré par des simples quotes2) et les chaines de caractères sont clôturées par des doubles quotes3). Cependant, la grande partie du framework de l’Objective-C n’utilise pas les chaines de caractères C-style très souvent. Les frameworks préfèrent déclarer les chaines de caractères avec les objets NSString.
La classe NSString offre un objet wrapper pour les chaines de caractères qui a tout les avantages que vous attendez, en incluant la gestion mémoire pour stocker des chaines de tailles arbitraires, le support de l’Unicode, le formatages printf-style, et plus encore. Parce que les chaines de caractères sont fréquemment utilisées, l’Objective-C apporte une notation raccourcie pour créer des objets NSString à partir de valeurs constantes. Pour utiliser ce raccourci, tout ce que vous avez a faire c’est de mettre le symbole @ devant la première double quote d’une chaine de caractères, comme dans l’exemple suivant :
NSString* myString = @"My String\n"; NSString* anotherString = [NSString stringWithFormat:@"%d %s", 1, @"String"]; // Create an Objective-C string from a C string NSString* fromCString = [NSString stringWithCString:"A C string" encoding:NSASCIIStringEncoding];
Comme dans la plupart des autres langages orientés objet, les classes en Objective-C apportent la base pour encapsuler les données avec les actions qui opèrent sur ces données. Un objet est simplement l’exécution de l’instance d’une classe, et qui a sa propre copie mémoire des variables de l’instance déclarées par cette classe et des pointeurs sur les méthodes de cette classe.
La déclaration d’une classe en Objective-C nécessite deux parties bien distinctes : l’interface et l’implémentation. La partie interface contient la déclaration de la classe et définie les variables de l’instance et les méthodes associées à cette classe. La partie implémentation contient le code des méthodes de la classe. La Figure 1 montre la syntaxe pour déclarer une classe appelé MyClasse, qui hérite de la classe NSObject la classe de base. La déclaration de la classe commence toujours par la directive de compilation @interface et fini avec la directive @end. Après le nom de la classe (et séparé par un deux points :) on trouve le nom de la classe parente. Les variables de l’instance (ou les membres) de la classe sont déclarées dans le bloc du code qui est délimité par des accolades ({ et }). Ensuite on retrouve la liste des méthodes déclaré par la classe. Un point virgule (;) marque la fin de chaque variable à instancié ou celle de la déclaration d’une méthode.
Le code suivant est la partie implémentation de MyClass de l’exemple précédent. Comme pour la déclaration de la classe, l’impémentation est identifiable ici par les deux directives de compilation, @implementation et @end. Ces directives apportent les informations de contexte dont le compilateur a besoin pour associer les méthodes incluses dans les directives avec la classe correspondante. C’est pourquoi la définition d’une méthode correspond à sa déclaration dans l’interface, sauf que cette dernière n’a pas de bloc de code.
@implementation MyClass - (id)initWithString:(NSString *) aName { if (self = [super init]) { count count = 0; data = nil; name = [aName copy]; return self; } } + (MyClass *)createMyClassWithString: (NSString *) aName { return [[[self alloc] initWithString:aName] autorelease]; } @end
Note: Bien que la déclaration de la classe précédente déclare seulement des méthodes, les classes peuvent aussi déclarer des propriétés. Pour plus d’informations sur les propriétés, consultez la section des “propriétés“.
Quand un objet est référencé par une variable, vous devez toujours utiliser un pointeur typé. L’Objective-C est capable d’utiliser les variables faiblement et fortement typés pour référencer un objet. Le pointeur fortement typé inclus le nom de la classe dans sa déclaration. Les pointeurs faiblement typés utilises plutôt le type id. Les pointeurs faiblement typés sont fréquemment utilisés comme par exemple dans les bibliothèques de classes, là où le type exacte de l’objet peut-être inconnu. Si vous êtes habitué à utiliser des langages fortements typés, vous pourriez avoir le raisonnement fallacieux que l’utilisation de variables faiblement typés est un source de problème, en réalité ce mécanisme apporte une formidable flexibilité et permet un plus grand dynamisme dans les programmes en Objective-C.
L’exemple suivant montre comment déclarer une variable fortement ou faiblement typé pour la classe MyClasse.
MyClass* myObject1; // Strong typing id myObject2; // Weak typing
Une classe en Objective-C peut déclarée deux types de méthodes : les méthodes de l’instance et les méthodes de la classe. Une méthode d’instance est une méthode dont l’exécution est associé à l’instance d’une classe. En d’autres mots, avant d’appeler une méthode de l’instance, vous devez en premier lieu instancié cette classe. Les méthodes d’une classe, par comparaison, n’ont pas besoin d’une instance pour être exécutées, mais nous reviendrons sur ce sujet plus tard.
La déclaration d’une méthode est constituée d’un identifiant de type de méthode, d’un type de retour, d’un ou plusieurs mots clefs de signatures, du type de paramètres et de son nom. La Figure 2 montre la déclaration de la méthode de l’instance insertObject:atIndex:. La déclaration est précédée par le signe moins (-), qui indique c’est une méthode de l’instance. Le nom actuel de la méthode (insertObject:atIndex:) est une concaténation de tout les mots clefs de signatures, en incluant les deux points ‘:‘. Le caractère deux points ‘:’ déclare la présence d’un paramètre. Si une méthode n’a pas de paramètres, vous devez ne pas mettre de deux points ‘:’ après le premier (et uniquement) mot clef de signature. Dans l’exemple, la méthode prend deux paramètres.
Quand vous voulez appeler une méthode, vous faite faire la commission via l’objet correspondant. Le messages dans ce cas est la signature de la méthode, avec le paramétrage dont la méthodes à besoin. Tout les messages que vous envoyez à un objet sont dynamiquement dispatché, grâce au mécanisme de polymorphisme des classes de l’Objective-C. En d’autre mots, Si une sous-classe défini une méthode avec la même signature que celle de sa classe mère, la sous-classe recevra le message d’abord et pourra (ou non) tranferer le message a son parent.
Les messages sont délimté par les crochets ([ et ]). A l’intérieur des crochets, l’objet qui reçoit le message est à gauche et le message (avec le paramétrage necessaire pour le message) est sur la droite. Par exemple, pour envoyer le message insertObject:atIndex: à un objet dans la variable myArray, vous devrez utiliser la syntaxe suivante:
[myArray insertObject:anObj atIndex:0];
Pour éviter de déclarer pléthore de vrariables locales pour stocker des résultats temporaires, l’Objective-C vous permet de nidifier (encapsuler) des messages. La valeur de retour de chacun de ces messages encapsulés est utilisé avec un paramètre, ou comme la cible d’un autre message. Par exemple, vous pouvez remplacer n’importe quelle variables utilisé dans l’exemple précédent par des messages pour récupérer les valeurs. En conséquence, si vous avez un autre objet appelé myAppObject qui lui même a des méthodes pour acceder un objet tableau et l’objet a inserer dans le tableau, vous pouvez ecrire l’exemple précédent de la manière suivante :
[[myAppObject getArray] insertObject:[myAppObject getObjectToInsert] atIndex:0];
Bien que dans l’exemple précédent les messages soient envoyés à une instance de la classe, vous pouvez aussi envoyer des messages à la classe elle même. Quand vous envoyez des messages à la classe, la méthode que vous écrivez doit être définie, comme une méthode de la classe plutôt qu’une méthode de l’instance. Vous pouvez penser que les méthode de classe sont quelque chose d’apparenté à (mais pas vraiment excatement comme) des membres statique dans une classe en C++.
Vous allez typiquement utilisé les méthodes de classe comme méthode usine pour créer des nouvelles instances de la classe ou pour accéder a une partie d’informations partagées associées à la classe. La syntaxe pour déclarer une méthode de classe est identique à celle de la méthode d’instance, avec une exception. Au lieu d’utiliser le signe moins (-) comme identifiant de type de méthode, vous utiliserez le signe plus (+).
L’exemple suivant montre l’utilisation d’une classe de méthode comme une méthode usine. Dans ce cas, la méthode arrayWithCapacity: est une méthode de la classe NSMutableArray qui alloue et initialise une nouvelle instance de la classe et la renvoi dans votre code.
NSMutableArray* myArray = nil; // nil is essentially the same as NULL // Create a new array and assign it to the myArray variable. myArray = [NSMutableArray arrayWithCapacity:0];
Les propriétés sont une convention de notation pour remplacer les accessor4). Les propriétés ne crées pas de nouvelles instances des variables dans votre déclaration de classe. C’est simplement une notation courte pour définir les méthodes pour accéder à instances de variables existantes. Les classes qui exposent une instances “virtuelle” peuvent utiliser la notation des propriétés plutôt que d’utiliser la syntaxe des getters et des setters. Les classes peuvent aussi utiliser les propriétés pour exposer une instance “virtuelle” d’une variable dont les morceaux de données sont supputées dynamiquement et pas vraiment stocké dans une variable.
Properties are a convenience notation used to replace accessor method declarations. Properties do not create new instance variables in your class declaration. They are simply a shorthand for defining methods that access existing instance variables. Classes that expose instance variables can do so using the property notation instead of using getter and setter syntax. Classes can also use properties to expose “virtual” instance variables—that is, pieces of data that are computed dynamically and not actually stored in instance variables.
Fonctionnellement parlant, les propriétés réduisent le code redondant que vous avez à écrire. Du au fait que la plus part des méthodes des accessor sont écritent de la même manière, les propriétés éliminent la nécessité de faire une distinction entre le setter et le getter pour chaques instances de variables de la classe. Alternativement, vous pouvez spécifier le comportement que vous souhaitez pour utiliser la déclaration des propriétés et ensuite synthétiser les méthodes getter et setter basées sur cette déclaration à la compilation.
Practically speaking, properties reduce the amount of redundant code you have to write. Because most accessor methods are implemented in similar ways, properties eliminate the need to provide a distinct getter and setter method for each instance variable exposed in the class. Instead, you specify the behavior you want using the property declaration and then synthesize actual getter and setter methods based on that declaration at compile time.
Vous incluez des déclarations d’une propriété avec les déclarations de méthodes dans votre interface. La définition basique utilise la directive de compilation @property suivi par le type d’informations et le nom de la propriété. Vous pouvez aussi configurer la propriété avec des options qui vous permettent de définir comment les méthodes accessor vont se comporter. L’exemple suivant vous montre quelques déclaration de propriétés :
You include property declarations with the method declarations in your class interface. The basic definition uses the @property compiler directive, followed by the type information and name of the property. You can also configure the property with custom options, which define how the accessor methods behave. The following example shows a few simple property declarations:
@property BOOL flag; @property (copy) NSString* nameObject; // Copy the object during assignment. @property (readonly) UIView* rootView; // Create only a getter method.
Un autre avantage des propriétés est que vous pouvez utiliser la syntaxe avec le point pour y accéder dans votre code, comme dans l’exemple suivant :
Another benefit of properties is that you can use dot syntax when accessing them in your code, as shown in the following example:
myObject.flag = YES; CGRect viewFrame = myObject.rootView.frame;
Bien que le nom de l’objets et le nom de propriété soit un peu étudié, cela démontre la fléxibilité des propriétés. La syntaxe avec le point masque le jeu d’appels de la méthode correspondantes. Chaque propriétés lisible est caché par une une méthode qui a le même nom que la propriété. Chaque propriété qui peut être modifiée est caché par une méthode supplémentaire de la forme setPropertyName:, où la première lettre de la propriété est la même que le nom de la propriété en capitalized. (Ces méthodes sont actuellement l’implémentation des propriétés et c’est la raison de pourquoi vous pouver inclure les declarations de propriété pour les attributs de votre classe qui ne sont pas caché par par une variable instanciée.) Pour implémenter le code précédent en utilisant les méthodes à la place des propriétés, vous devriez écrire le code suivant :
Although the object and property names in the preceding example are contrived, they demonstrate the flexibility of properties. The dot syntax actually masks the corresponding set of method calls. Each readable property is backed by a method with the same name as the property. Each writable property is backed by an additional method of the form setPropertyName:, where the first letter of the property name is capitalized. (These methods are the actual implementation of properties and are the reason you can include property declarations for attributes of your class that are not backed by instance variables.) To implement the preceding code using methods instead of properties, you would write the following code:
[myObject setFlag:YES]; CGRect viewFrame = [[myObject rootView] frame];
Pour plus d’informations sur comment déclarer des propriétés dans vos classe, lisez “Properties” in The Objective-C 2.0 Programming Language.
For information on how to declare properties in your own classes, read “Properties” in The Objective-C 2.0 Programming Language.
Protocols and Delegates
Un protocle déclare des méthodes qui peuvent être implémenté dans n’importe quelle classes. Les protocoles ne sont pas des classe en soit. C’est simplement la définition d’une interface pour d’autres objets
qui eux contiendront l’implémentation. Quand vous implémentez une méthode d’un protocole dans une de vos classes, votre classe est dites conforme à ce protocole.
A protocol declares methods that can be implemented by any class. Protocols are not classes themselves. They simply define an interface that other objects are responsible for implementing. When you implement the methods of a protocol in one of your classes, your class is said to conform to that protocol.
Sur OS iPhone, les protocoles sont souvent utiliser pour implémenter des objets normés. Un objet normés est un objets qui agit comme une représentation, ou en coordination avec un autre objet. La meilleure façon de voir les interactions entre les protocoles, les objets normés, et les autres objets et de voir un exemple.
In iPhone OS, protocols are used frequently to implement delegate objects. A delegate object is an object that acts on behalf of, or in coordination with, another object. The best way to look at the interplay between protocols, delegates, and other objects is to look at an example.
La classe UIApplication implémente une fonctionnalité indispensable de l’application. Au lieu de vous forcer à recevoir les notifications à propos de l’état courant de l’application sur une sous-classe de UIApplication, la classe elle-même délivre ces notifications en utilisant les méthodes spécifiques de sont objet normé associé. Un objet qui implémente une méthode du protocole UIApplicationDelegate peut recevoire ces notifications et apporter une réponse approprié.
The UIApplication class implements the required behavior of an application. Instead of forcing you to subclass UIApplication to receive simple notifications about the current state of the application, the UIApplication class delivers those notifications by calling specific methods of its assigned delegate object. An object that implements the methods of the UIApplicationDelegate protocol can receive those notifications and provide an appropriate response.
La déclaration d’un protocle ressemble à la façon de déclarer une interface de classe, avec pour exception que les protocoles n’ont pas de classes parentes et ne peuvent définir des variables instanciées. L’exemple suivant montre la déclaration d’un protocole avec une méthode :
The declaration of a protocol looks similar to that of a class interface, with the exceptions that protocols do not have a parent class and they do not define instance variables. The following example shows a simple protocol declaration with one method:
@protocol MyProtocol - (void)myProtocolMethod; @end
Dans le cas beaucoup de protocole normée, l’adoption d’un protocole est simplement une question de méthodes d’implentations qui définissent ce protocole. Quelques protocoles exigent qu’il soit explicitement spécifié que vous supportiez ce protocole, et les protocoles peuvent définir des méthodes obligatoires ou facultatives. Quand vous avancerez plus loin dans vos développement, vous devriez passe un peu de temps à en apprendre un peu sur les protocoles et comment ils sont utilisés en lisant “Protocols” in The Objective-C 2.0 Programming Language.
In the case of many delegate protocols, adopting a protocol is simply a matter of implementing the methods defined by that protocol. There are some protocols that require you to state explicitly that you support the protocol, and protocols can specify both required and optional methods. As you get further into your development, however, you should spend a little more time learning about protocols and how they are used by reading “Protocols” in The Objective-C 2.0 Programming Language.
For More Information
The preceding information was intended primarily to familiarize you with the basics of the Objective-C language. The subjects covered here reflect the language features you are most likely to encounter as you read through the rest of the documentation. These are not the only features of the language though, and you are encouraged to read more about the language in The Objective-C 2.0 Programming Language. Browse Getting Started Documents