Objective-C tire sa syntaxe d’objet de Smalltalk. Toute la syntaxe pour les opérations non orientées objet (y compris les variables primitives, le prétraitement, les expressions, les déclarations de fonction et les appels de fonction) est identique à celles de C, tandis que la syntaxe pour les fonctionnalités orientées objet est une implémentation de la messagerie de style Smalltalk.
MessagesEdit
le modèle Objective-C de la programmation orientée objet est basé sur le passage de messages aux instances d’objet. En Objective-C, on n’appelle pas de méthode; on envoie un message., Ceci est différent du modèle de programmation de style Simula utilisé par C++. La différence entre ces deux concepts réside dans la façon dont le code référencé par la méthode ou le nom du message est exécuté. Dans un langage de type Simula, le nom de la méthode est dans la plupart des cas lié à une section de code de la classe cible par le compilateur. Dans Smalltalk et Objective-C, la cible d’un message est résolue à l’exécution, l’objet récepteur interprétant lui-même le message., Une méthode est identifiée par un sélecteur ou SEL – un identifiant unique pour chaque nom de message, souvent juste une chaîne terminée par NUL représentant son nom-et résolue en un pointeur de méthode C l’implémentant: un IMP. Une conséquence de ceci est que le système de passage de message n’a aucune vérification de type. L’objet pour lequel le message est dirigé — le récepteur n’est pas garanti pour répondre à un message, et si elle ne le fait pas, il lève une exception.,
l’Envoi du message de la méthode à l’objet pointé par le pointeur obj nécessiterait le code suivant en C++:
obj->method(argument);
En Objective-C, c’est écrit comme suit:
;
La « méthode » appel se traduit par le compilateur à la objc_msgSend(id auto, SEL op …) famille de fonctions d’exécution. Différentes implémentations gèrent les ajouts modernes comme super. Dans les familles GNU, cette fonction est nommée objc_msg_sendv, mais elle a été dépréciée en faveur d’un système de recherche moderne sous objc_msg_lookup.,
les Deux styles de programmation ont leurs forces et leurs faiblesses. La programmation orientée objet dans le style Simula (C++) permet un héritage multiple et une exécution plus rapide en utilisant la liaison à la compilation chaque fois que possible, mais elle ne prend pas en charge la liaison dynamique par défaut. Il force également toutes les méthodes à avoir une implémentation correspondante à moins qu’elles ne soient abstraites. La programmation de style Smalltalk telle qu’utilisée dans Objective-C permet aux messages de ne pas être mis en œuvre, la méthode étant résolue à son implémentation au moment de l’exécution., Par exemple, un message peut être envoyé à une collection d’objets, dont certains seulement sont censés répondre, sans crainte de produire des erreurs d’exécution. Le passage de Message ne nécessite pas non plus qu’un objet soit défini au moment de la compilation. Une implémentation est toujours requise pour que la méthode soit appelée dans l’Objet dérivé. (Voir la section typage dynamique ci-dessous pour plus d’avantages de la liaison dynamique (tardive).)
Interfaces and implementationsEdit
Objective-C exige que l’interface et l’implémentation d’une classe soient dans des blocs de code déclarés séparément., Par convention, les développeurs placent l’interface dans un fichier d’en-tête et l’implémentation dans un fichier de code. Les fichiers d’en-tête, normalement suffixés .h, sont similaires aux fichiers D’en-tête C tandis que les fichiers d’implémentation (méthode), normalement suffixés .m, peut être très similaire aux fichiers de code C.
InterfaceEdit
ceci est analogue aux déclarations de classe utilisées dans d’autres langages orientés objet, tels que c++ ou Python.
L’interface d’une classe est généralement définie dans un fichier d’en-tête. Une convention courante est de nommer le fichier d’en-tête après le nom de la classe, par exemple Ball.,h contiendrait l’interface de la classe Ball.
Une déclaration d’interface prend la forme:
dans ce qui précède, les signes plus désignent les méthodes de classe, ou les méthodes qui peuvent être appelées sur la classe elle-même (pas sur une instance), et les signes moins désignent les méthodes d’instance, qui ne peuvent être appelées que sur une instance particulière de la classe. Les méthodes de classe n’ont pas non plus accès aux variables d’instance.,
le code ci-dessus est à peu près équivalent à L’interface c++ suivante:
notez que instanceMethod2With2Parameters:param2_callName: démontre l’entrelacement des segments de sélecteur avec des expressions d’argument, pour lesquelles il n’y a pas d’équivalent direct en C / C++.
Les types de retour peuvent être n’importe quel type C standard, un pointeur vers un objet Objective-C Générique, un pointeur vers un type d’objet spécifique tel que NSArray *, NSImage * ou NSString*, ou un pointeur vers la classe à laquelle appartient la méthode (instancetype). Le type de retour par défaut est L’id de type Objective-C Générique.,
les arguments de la méthode commencent par un nom marquant l’argument qui fait partie du nom de la méthode, suivi d’un deux-points suivi du type d’argument attendu entre parenthèses et du nom de l’argument. L’étiquette peut être omis.
une dérivée de la définition de l’interface est la catégorie, qui permet d’ajouter des méthodes aux classes existantes.
ImplementationEdit
L’interface déclare uniquement l’interface de classe et non les méthodes elles-mêmes: le code réel est écrit dans le fichier d’implémentation., Les fichiers d’implémentation (méthode) ont normalement l’extension .m
, qui signifiait à l’origine « messages ».
@implementation classname+ (return_type)classMethod { // implementation}- (return_type)instanceMethod { // implementation}@end
les Méthodes sont écrites à l’aide de leurs déclarations interface.La comparaison Objective-C et C:
- (int)method:(int)i { return ;}
int function(int i) { return square_root(i);}
La syntaxe permet de pseudo-désignation des arguments.
Les représentations internes d’une méthode varient entre les différentes implémentations D’Objective-C., Si myColor est de la classe Color, la méthode d’instance-changeColorToRed: green: blue: peut être étiquetée en interne _i_Color_changeColorToRed_green_blue. Le i doit faire référence à une méthode d’instance, avec la classe, puis les noms de méthode ajoutés et les deux-points changés en traits de soulignement. Comme l’ordre des paramètres fait partie du nom de la méthode, il ne peut pas être modifié pour convenir au style de codage ou à l’expression comme avec les vrais paramètres nommés.
cependant, les noms internes de la fonction sont rarement utilisés directement. Généralement, les messages sont convertis en appels de fonction définis dans la bibliothèque D’exécution Objective-C., On ne sait pas nécessairement au moment du lien quelle méthode sera appelée car la classe du récepteur (l’objet Envoyé le message) n’a pas besoin d’être connue avant l’exécution.
InstantiationEdit
Une fois qu’une classe Objective-C est écrite, elle peut être instanciée. Cela se fait en allouant d’abord une instance non initialisée de la classe (un objet), puis en l’initialisant. Un objet n’est pas entièrement fonctionnel tant que les deux étapes n’ont pas été terminées., Ces étapes doivent être effectuées avec une seule ligne de code afin qu’il n’y ait jamais d’objet alloué qui n’ait pas subi d’initialisation (et parce qu’il est imprudent de conserver le résultat intermédiaire car -init
peut renvoyer un objet différent de celui sur lequel il est appelé).,
Instanciation avec la valeur par défaut sans paramètre d’initialisation:
MyObject *foo = init];
Instanciation d’un initialiseur:
MyObject *foo = initWithString:myString];
Dans le cas où aucune initialisation personnalisée est effectuée, la « nouvelle » méthode peut souvent être utilisé à la place de l’alloc-init messages:
MyObject *foo = ;
en outre, certaines classes en œuvre de la méthode de classe initialiseurs., Comme +new
, ils combinent +alloc
et -init
, mais à la différence de +new
, ils reviennent un autoreleased instance. Certains initialiseurs de méthode de classe prennent des paramètres:
MyObject *foo = ;MyObject *bar = ;
le message alloc alloue suffisamment de mémoire pour contenir toutes les variables d’instance d’un objet, définit toutes les variables d’instance à zéro et transforme la mémoire en instance de la classe; à aucun moment pendant l’initialisation, la mémoire,
le message d’initialisation effectue la configuration de l’instance lors de la création. La méthode init est souvent écrit comme suit:
- (id)init { self = ; if (self) { // perform initialization of object here } return self;}
Dans l’exemple ci-dessus, l’avis de la id
le type de retour. Ce type signifie « pointeur vers n’importe quel objet » dans Objective-C (Voir la section de typage dynamique).
le modèle d’initialisation est utilisé pour s’assurer que l’objet est correctement initialisé par sa superclasse avant que la méthode init effectue son initialisation., Il effectue les actions suivantes:
- self = envoie à l’instance de superclasse un message d’initialisation et affecte le résultat à self (pointeur vers l’objet courant).
- if (self)vérifie si le pointeur d’objet retourné est valide avant d’effectuer une initialisation.
- retourne selfReturns la valeur de self à l’appelant.
un pointeur d’objet non valide a la valeur nil; les instructions conditionnelles comme « if » traitent nil comme un pointeur null, de sorte que le code d’initialisation ne sera pas exécuté s’il est retourné nil., S’il y a une erreur dans l’initialisation, la méthode init doit effectuer tout nettoyage nécessaire, y compris l’envoi d’un message « release » À self, et renvoyer nil pour indiquer que l’initialisation a échoué. Toute vérification de telles erreurs ne doit être effectuée qu’après avoir appelé l’initialisation de la superclasse pour s’assurer que la destruction de l’objet sera effectuée correctement.
si une classe a plus d’une méthode d’initialisation, une seule d’entre elles (l ‘ « initialiseur désigné ») doit suivre ce modèle; les autres doivent appeler l’initialiseur désigné au lieu de l’initialiseur de superclasse.,
ProtocolsEdit
dans d’autres langages de programmation, ceux-ci sont appelés « interfaces ».
Objective-C a été étendu à NeXT pour introduire le concept d’héritage multiple de spécification, mais pas de mise en œuvre, grâce à l’introduction de protocoles. Il s’agit d’un modèle réalisable soit en tant que classe de base abstraite héritée multiple en C++, soit en tant qu ‘ « interface » (comme en Java et C#). Objective – C utilise des protocoles ad hoc appelés protocoles informels et des protocoles imposés par le compilateur appelés protocoles formels.,
un protocole informel est une liste de méthodes qu’une classe peut choisir d’implémenter. Il est spécifié dans la documentation, car elle n’a aucune présence dans la langue. Les protocoles informels sont implémentés en tant que Catégorie (voir ci-dessous) sur NSObject et incluent souvent des méthodes facultatives qui, si elles sont implémentées, peuvent changer le comportement d’une classe. Par exemple, une classe de champ de texte peut avoir un délégué qui implémente un protocole informel avec une méthode facultative pour effectuer l’auto-complétion du texte tapé par l’utilisateur., Le champ de texte découvre si le délégué implémente cette méthode (via la réflexion) et, si c’est le cas, appelle la méthode du délégué pour prendre en charge la fonctionnalité de remplissage automatique.
un protocole formel est similaire à une interface en Java, C# et Ada 2005. C’est une liste de méthodes que n’importe quelle classe peut se déclarer à implémenter. Les Versions D’Objective – C antérieures à 2.0 nécessitaient qu’une classe implémente toutes les méthodes d’un protocole qu’elle se déclare adopter; le compilateur émettra une erreur si la classe n’implémente pas toutes les méthodes de ses protocoles déclarés. Objectif-C 2.,0 ajout du support pour marquer certaines méthodes dans un protocole facultatif, et le compilateur n’appliquera pas l’implémentation des méthodes facultatives.
Une classe doit être déclarée pour implémenter ce protocole pour être considérée comme conforme. Ce n’est détectable au moment de l’exécution. Les protocoles formels ne peuvent pas fournir d’implémentations; ils assurent simplement aux appelants que les classes conformes au protocole fourniront des implémentations. Dans la bibliothèque NeXT/Apple, les protocoles sont fréquemment utilisés par le système D’objets distribués pour représenter les capacités d’un objet s’exécutant sur un système distant.,
La syntaxe
@protocol NSLocking- (void)lock;- (void)unlock;@end
indique qu’il y a de l’idée abstraite de verrouillage. En indiquant dans la définition de classe que le protocole est implémenté,
@interface NSLock : NSObject <NSLocking>// ...@end
Les instances de NSLock affirment qu’elles fourniront une implémentation pour les deux méthodes d’instance.
Dynamic typingEdit
Objective-C, comme Smalltalk, peut utiliser le typage dynamique: un objet peut recevoir un message qui n’est pas spécifié dans son interface., Cela peut permettre une flexibilité accrue, car il permet à un objet de « capturer » un message et d’envoyer le message à un autre objet qui peut répondre au message de manière appropriée, ou de même envoyer le message à un autre objet. Ce comportement est connu sous le nom de transfert de message ou de délégation (voir ci-dessous). Alternativement, un gestionnaire d’erreurs peut être utilisé dans le cas où le message ne peut pas être transféré. Si un objet ne transmet pas un message, n’y répond pas ou ne gère pas une erreur, le système générera une exception d’exécution., Si les messages sont envoyés à nil (le pointeur d’objet null), ils seront ignorés silencieusement ou déclencheront une exception Générique, selon les options du compilateur.
des informations de typage statique peuvent également éventuellement être ajoutées aux variables. Ces informations sont ensuite vérifiées au moment de la compilation. Dans les quatre déclarations suivantes, des informations de type de plus en plus spécifiques sont fournies. Les instructions sont équivalentes à l’exécution, mais les informations supplémentaires permettent au compilateur d’avertir le programmeur si l’argument transmis ne correspond pas au type spécifié.,
- (void)setMyValue:(id)foo;
Dans la déclaration ci-dessus, foo peut être de n’importe quelle classe.
- (void)setMyValue:(id<NSCopying>)foo;
Dans la déclaration ci-dessus, foo peut être une instance d’une classe qui est conforme à la balise NSCopying
protocole.
- (void)setMyValue:(NSNumber *)foo;
Dans la déclaration ci-dessus, toto doit être une instance de la NSNumber classe.
- (void)setMyValue:(NSNumber<NSCopying> *)foo;
dans l’instruction ci-dessus, foo doit être une instance de la classe NSNumber et doit être conforme au protocoleNSCopying
.,
dans Objective-C, Tous les objets sont représentés sous forme de pointeurs et l’initialisation statique n’est pas autorisée. L’objet le plus simple est le type vers lequel id (objc_obj *) pointe, qui n’a qu’un pointeur isa décrivant sa classe. D’autres types de C, comme les valeurs et les structures, sont inchangés car ils ne font pas partie du système d’objets. Cette décision diffère du modèle d’objet C++, où les structures et les classes sont unies.
ForwardingEdit
Objective-C permet l’envoi d’un message à un objet qui ne peut pas répondre., Plutôt que de répondre ou simplement déplacer le message, un objet peut transférer le message à un objet qui peut répondre. Le transfert peut être utilisé pour simplifier la mise en œuvre de certains modèles de conception, tels que le modèle observateur ou le modèle proxy.
le runtime Objective-C spécifie une paire de méthodes dans Object
Un objet souhaitant implémenter le transfert n’a besoin que de remplacer la méthode de transfert par une nouvelle méthode pour définir le comportement de transfert. La méthode d’action performv:: n’a pas besoin d’être remplacée, car cette méthode effectue simplement une action basée sur le sélecteur et les arguments., Notez le type SEL
, qui est le type de messages dans Objective-C.
Remarque: Dans OpenStep, Cocoa et GNUstep, les frameworks couramment utilisés par Objective-C, on n’utilise pas la classe Object. La méthode – (void)forwardInvocation:(NSInvocation *)aninvocation de la classe NSObject est utilisée pour effectuer le transfert.
ExampleEdit
Voici un exemple de programme qui démontre les bases du transfert.
transitaire.H transitaire.m destinataire.h
#import <objc/Object.h>// A simple Recipient object.@interface Recipient : Object- (id)hello;@end
Destinataire.m
#import "Recipient.h"@implementation Recipient- (id)hello { printf("Recipient says hello!\n"); return self;}@end
principal.,m
NotesEdit
lorsqu’il est compilé à l’aide de gcc, le compilateur signale:
le compilateur signale le point fait précédemment, que Forwarder ne répond pas aux messages hello. Dans ce cas, il est prudent d’ignorer l’avertissement depuis que le transfert a été implémenté. L’exécution du programme produit cette sortie:
$ ./a.outRecipient says hello!
CategoriesEdit
lors de la conception D’Objective-C, l’une des principales préoccupations était la maintenabilité des grandes bases de code., Expérience de la programmation structurée monde a montré que l’un des principaux moyens d’améliorer le code est de le décomposer en petits morceaux. Objective – C a emprunté et étendu le concept de catégories des implémentations Smalltalk pour aider à ce processus.
de plus, les méthodes d’une catégorie sont ajoutées à une classe au moment de l’exécution. Ainsi, les catégories permettent au programmeur d’ajouter des méthodes à une classe existante – une classe ouverte – sans avoir besoin de recompiler cette classe ou même d’avoir accès à son code source., Par exemple, si un système ne contient pas de correcteur orthographique dans son implémentation de chaîne, il peut être ajouté sans modifier le code source de chaîne.
les Méthodes dans les catégories deviennent indiscernables des méthodes dans une classe lorsque le programme est exécuté. Une catégorie a un accès complet à toutes les variables d’instance de la classe, y compris les variables privées.
Si une catégorie déclare une méthode avec la même signature de la méthode comme une méthode dans une classe, la catégorie de la méthode adoptée. Ainsi, les catégories peuvent non seulement ajouter des méthodes à une classe, mais également remplacer les méthodes existantes., Cette fonctionnalité peut être utilisée pour corriger des bogues dans d’autres classes en réécrivant leurs méthodes, ou pour provoquer une modification globale du comportement d’une classe au sein d’un programme. Si deux catégories ont des méthodes avec le même nom mais des signatures de méthode différentes, il n’est pas défini quelle méthode de catégorie est adoptée.
D’autres langues ont tenté d’ajouter cette fonctionnalité de différentes manières. TOM a poussé le système Objective-C Un peu plus loin et a également permis l’ajout de variables. D’autres langages ont plutôt utilisé des solutions basées sur des prototypes, le plus notable étant Self.
Le C# et Visual Basic.,Les langages NET implémentent des fonctionnalités superficiellement similaires sous la forme de méthodes d’extension, mais celles-ci n’ont pas accès aux variables privées de la classe. Ruby et plusieurs autres langages de programmation dynamiques se réfèrent à la technique comme « patching de singe ».
Logtalk implémente un concept de catégories (en tant qu’entités de première classe) qui sous-estime la fonctionnalité des catégories Objective-C (les catégories Logtalk peuvent également être utilisées comme unités de composition à grain fin lors de la définition, par exemple, de nouvelles classes ou prototypes; en particulier, une catégorie Logtalk peut être importée virtuellement par n’importe quel,
exemple d’utilisation de categoriesEdit
cet exemple construit une classe entière, en définissant d’abord une classe de base avec uniquement des méthodes accessor implémentées, et en ajoutant deux catégories, arithmétique et affichage, qui étendent la classe de base. Bien que les catégories puissent accéder aux membres de données privées de la classe de base, il est souvent recommandé d’accéder à ces membres de données privées via les méthodes accessor, ce qui permet de garder les catégories plus indépendantes de la classe de base. La mise en œuvre de tels accesseurs est une utilisation typique des catégories. Une autre consiste à utiliser des catégories pour ajouter des méthodes à la classe de base., Cependant, il n’est pas considéré comme une bonne pratique d’utiliser des catégories pour le remplacement des sous-classes, également connu sous le nom de patch de singe. Les protocoles informels sont implémentés en tant que catégorie sur la classe NSObject de base. Par convention, les fichiers contenant des catégories qui étendent les classes de base prendront le nom BaseClass + ExtensionClass.h.
Integer.h
#import <objc/Object.h>@interface Integer : Object { int integer;}- (int)integer;- (id)integer:(int)_integer;@end
entier.m entier + arithmétique.h
#import "Integer.h"@interface Integer (Arithmetic)- (id) add: (Integer *) addend;- (id) sub: (Integer *) subtrahend;@end
entier+arithmétique.m entier + affichage.h
#import "Integer.h"@interface Integer (Display)- (id) showstars;- (id) showint;@end
entier+affichage.m principal.,m
NotesEdit
la Compilation est effectuée, par exemple, par:
gcc -x objective-c main.m Integer.m Integer+Arithmetic.m Integer+Display.m -lobjc
on peut expérimenter en omettant le #import « entier+arithmétique.h » et les lignes et omettant entier + arithmétique.m lors de la compilation. Le programme fonctionnera toujours. Cela signifie qu’il est possible de mélanger et de faire correspondre des catégories ajoutées si nécessaire; si une catégorie n’a pas besoin d’avoir une certaine capacité, elle ne peut tout simplement pas être compilée.
PosingEdit
Objective-C permet à une classe de remplacer complètement une autre classe dans un programme. La classe de remplacement est dite « poser comme » la classe cible.,
Class posing a été déclaré obsolète avec Mac OS X v10.5 et n’est pas disponible dans l’exécution 64 bits. Une fonctionnalité similaire peut être obtenue en utilisant la méthode swizzling dans les catégories, qui échange l’implémentation d’une méthode avec une autre qui a la même signature.
pour les versions prenant toujours en charge posing, tous les messages envoyés à la classe cible sont plutôt reçus par la classe posing. Il existe plusieurs restrictions:
- Une classe ne peut se présenter que comme l’une de ses superclasses directes ou indirectes.,
- La classe posing ne doit pas définir de nouvelles variables d’instance absentes de la classe cible (bien qu’elle puisse définir ou remplacer des méthodes).
- La classe cible n’a peut-être reçu aucun message avant la pose.
poser, de la même manière que les catégories, permet une augmentation globale des classes existantes. La pose permet deux caractéristiques absentes des catégories:
- Une classe de pose peut appeler des méthodes surchargées via super, incorporant ainsi l’implémentation de la classe cible.
- Une classe posant peut remplacer les méthodes définies dans les catégories.,
Par exemple,
cela intercepte chaque appel de setMainMenu à NSApplication.
#importEdit
dans le langage C, la directive#include
pre-compile entraîne toujours l’insertion du contenu d’un fichier dans la source à ce moment-là. Objective-C a la directive#import
, équivalente sauf que chaque fichier n’est inclus qu’une seule fois par unité de compilation, ce qui évite le besoin de gardes d’inclusion.