Programmation MacOSX / ios Master Ingénierie Informatique 2011-2012 Jean-Baptiste.Yunès@liafa.jussieu.fr
deux extensions objets de C : C++ (Stroustrup) Objective-C (Cox & Love) ajout de constructions à la Smalltalk au-dessus du C (C ObjC) dynamisme (dispatch, typage, chargement) langage de base pour NeXTstep, GNUstep, OpenStep, MacOSX/iOS 2
décrit dans : The Objective-C 2.0 Programming Language téléchargeable/consultable sur le site des développeurs Apple intégré à la documentation de xcode Pas de bibliothèque standard Objective-C utiliser celle du C de Foundation ou Cocoa
la version 2.0 du langage ne peut être employée sous une version inférieure à Mac OS X 10.5 (leopard) sinon se reporter à la version 1.0 consulter aussi : Object-Oriented Programming with Objective-C Objective-C 2.0 Runtime Reference Objective-C Release Notes Garbage Collection Programming Guide 4
gcc supporte Objective-C (en plus de C et C++) l extension.m pour les codes sources Objective-C est reconnue la bibliothèque objc est à employer pour l édition de liens ou objc_gc utiliser -Wno-import -fobjc-gc pour réaliser l édition de lien avec un framework : -framework Foundation ou alors (plus simple) employer xcode 5
Les mots-clés d Objective-C : @catch, @class, @encode, @end, @finally, @implementation, @interface, @private, @protected, @protocol, @public, @selector, @synchronized, @throw, @try (+@defs désormais sans usage) Objective-C 2.0 : @property, @dynamic, @synthesize, @optional, @required 6
Il existe 5 types définis dans le runtime objective-c : SEL : le type des sélecteurs BOOL : YES et NO IMP : pointeurs vers fonctions C Class : pointeurs vers objets-classe, Nil id : pointeurs vers objets, nil @class permet de déclarer un type classe 7
id le type des identificateurs d objet on rappelle que dans le paradigme objet les objets sont caractérisés par......leur identificateur! 8
Les références d objets ont pour type soit un pointeur vers un des types de l objet (syntaxe C/C++) soit un type référence générique id Exemple : id unobjet; La constante prédéfinie nil (ou 0) représente une référence vers l objet vide/nul Il s agit essentiellement d un pointeur vers les données de l objet (void *) 9
Attention: le type id est un type générique (il ne nécessite pas de transtypage) Pour connaître le type d un objet on peut utiliser sa variable d instance isa qui désigne sa classe ce champ est présent dans tous les objets normalement constitués d Objective-C Objective-C est un langage typé dynamiquement (pour les objets) 10
Les messages objective-c la métaphore du paradigme objet est pertinente pour le langage on n appelle pas une méthode on envoie un message à un objet afin qu il réagisse en exécutant une méthode adéquate (i.e. un algorithme dynamique est utilisé pour déterminer la méthode correspondant au message) 11
syntaxe pour l envoi des messages : [receveur selecteur]; par exemple [dessin afficher]; l emploi du sélecteur afficher provoquera (probablement) l appel à la méthode afficher de l objet dessin 12
Il est très important de distinguer ici envoi de message appel de méthode L envoi d un message à un objet déclenche un mécanisme de recherche dans l objet receveur d une méthode correspondant au sélecteur afin de répondre au message 13
c est un mécanisme dynamique sur lequel le programmeur peut intervenir... le receveur et le sélecteur peuvent être tous deux des variables à la compilation ces choses peuvent être indéterminées 14
les méthodes peuvent recevoir un(des) argument(s), les messages permettant de spécifier des valeurs pour ces arguments, la forme syntaxique est : [pile empile:unevaleur]; ou encore : [grille getcase:12 :4]; les arguments peuvent être nommés comme dans : [grille getvaleurcolonne:12 ligne:4]; 15
les méthodes peuvent aussi renvoyer des valeurs, on peut donc récupérer la valeur renvoyée par la méthode : int v; v = [unepile depile]; il n est pas interdit d envoyer un message à l objet vide/nul l effet produit est de renvoyer 0 (ou une structure remplie de 0 dans certains cas) 16
objet-classe : la définition d une classe créé un objet (unique) la représentant un objet-classe est parfois appelé objet usine (factory object), c est un pattern (se reporter au «Design Patterns» de Gamma et al. 17
Conventions d écriture: UneClasse uneméthode unevariabledinstance _unevariableprivée _UneClassePrivée 18
Les classes données champs opérations méthodes 19
la déclaration d une classe Objective-C consiste à déclarer les données d instances et certaines des méthodes qui pourront être appelées (pas nécessaire de déclarer toutes les méthodes) : c est une interface attention interface objc = classe Java la définition consiste en l implémentation des méthodes 20
l interface d une classe de nom MaClasse est (habituellement) déclarée dans : MaClasse.h et son implémentation définie dans : MaClasse.m 21
la déclaration (de l interface) a la forme générale suivante : @interface MaClasse { // déclarations de données d instance } // déclarations de méthodes d instance ou de classe @end la déclaration d une méthode d instance doit être précédée du caractère - la déclaration d une méthode de classe doit être précédée du caractère + 22
@interface MaClasse { int unedonnée; // par défaut @protected! } - (void)amethod; - (int)anothermethod:(int)x; - (int)setwitdh:(int)w andheight:(int)h; @end type de l argument type de la valeur de retour nom de l argument sélecteur 23
une méthode comme : - (void)setwidth:(int)w andheight:(int)h; pourra être atteinte par envoi d un message comme : [o setwidth:13 andheight:89]; attention, si pas de type de retour déclaré le type par défaut est id déclaration anticipée (forward déclaration) @class Voiture, Habitation; 24
attention, ne pas confondre les + et - avec ceux d UML... attention, il n y a pas de données de classe (pas de variables statiques de classe) il faut donc employer des variables globales ordinaires 25
l implémentation de la classe MaClasse a pour forme générale : #import MaClasse.h @implementation MaClasse // définitions des méthodes @end 26
#import <MaClasse.h> @implementation MaClasse - (void)amethod { // do something } - (int)anothermethod:(int)x { // think different } - (int)setwitdh:(int)w andheight:(int)h { // be inventive } @end 27
attention la définition d une méthode doit suivre exactement le modèle de sa déclaration l objet courant s appelle self [self doit]; l objet courant vu comme objet typé par sa super-classe s appelle super [super init]; 28
l opérateur d accès aux variables d instance -> peut être utilisé, à condition que l objet en question soit du même type que celui du contexte de la méthode attention son usage est déconseillé autant que possible (voir plus loin), car il courtcircuite les accesseurs on peut utiliser des adjectifs qualifiant les données @private, @protected (par défaut), @public, @package (64 bits seulement) 29
initialisation des variables globales par utilisation de la méthode de classe +(void)initialize; qui est appelée automatiquement : avant toute autre méthode à l endroit (au moment) de la première utilisation de la classe 30
attention, il est de la responsabilité du programmeur d assurer que la logique ne s exécute qu une seule fois + (void)initialize { } static BOOL initialized = NO; if (!initialized) { // perform initialization here... initialized = YES; attention, il ne faut pas appeler initialize pour la super classe 31
L héritage l héritage n est pas la technique objet la plus employée les classes des diverses API utilisent l héritage mais sont conçues de sorte qu il ne soit généralement pas nécessaire d utiliser l héritage c est la délégation qui est encouragée 32
si l on ne déclare pas de super classe, la classe est une classe racine (très fortement déconseillé) il est conseillé d utiliser systématiquement NSObject comme super classe. L import s effectue par : #import <Foundation/NSObject.h> ou mieux #import <Foundation/Foundation.h> ou #import <Foundation/Cocoa.h> 33
NS??? C est un préfixe hérité de NextStep, on en rencontrera un autre pour l iphone : UI l héritage depuis la classe NSObject permet de bénéficier de nombreux services... La variable d instance isa (protegée) est héritée par tous les objets le pattern KVC... 34
l héritage (toujours simple) s exprime sous la forme : @interface UneClasse : SaSuperClasse // blablabla... @end attention, les données membres doivent utiliser des identificateurs distincts de ceux de la super-classe... 35
la liaison des méthodes est dynamique (aka méthodes virtuelles) comme en Java on appelle la méthode la plus spécifique (la plus basse dans la hiérarchie des types de l objet) qui correspond au sélecteur attention car c est bien le sélecteur qui compte pour sélectionner une méthode (donc pas les types des arguments...) 36
Les catégories elles constituent une alternative pratique à l héritage dont l emploi n est pas particulièrement recommandé 37
les catégories permettent d étendre les classes existantes c est un mécanisme d extension de classe (spécialisation conceptuelle) on rajoute des méthodes supplémentaires à une classe donnée ce mécanisme est souvent utilisé comme une alternative aux sous-classes 38
// MaClasse+Catégorie.h #import <MaClasse.h> @interface MaClasse (Catégorie) // déclaration de méthodes @end // MaClasse+Catégorie.m #import <MaClasse+Catégorie.h> @implementation MaClasse (Catégorie) // définition de méthodes @end 39
il est important de noter que ce mécanisme étend bien la classe sans que l utilisateur de la classe en ait conscience l utilisateur de la classe originelle continue de la manipuler comme avant quand bien même elle a été modifiée noter aussi que ce mécanisme ne permet que d ajouter des méthodes, pas de données 40
Les protocoles ce terme provient du paradigme objet et désigne le protocole employé par les objets pour communiquer entre eux il s agit donc de décrire quels services les objets rendent-ils à leur environnement cela correspond au concept d interface Java les classes peuvent se déclarer conforme à un protocole objet donné 41
les protocoles formels (Protocols) @protocol MonProtocole @end // déclarations de méthodes il est possible de définir des obligations à remplir vis-à-vis de la définition : @required @optional les protocoles informels sont constitués des catégories 42
objet-protocole Protocol *prot = @protocol(monprotocole); adoption d un protocole par une classe @interface Classe : SuperClasse < Protocole[,...] > @interface Classe ( Catégorie ) < Protocole[,...] > la méthode d instance ou de classe conformstoprotocol permet de déterminer si une classe ou une instace est conforme à un protocole donné 43
types conformes à un protocole : id <Imprimable> unimprimable; Image <Imprimable> *monimageimprimable; type <protocole> variable; hiérarchie de protocoles : @protocol Protocole < Prot1, Prot2, > 44
L instanciation contrairement aux ambigüités des langages objets «mainstream», le processus d instanciation d objets nécessite d expliciter les deux étapes : l allocation (pattern factory) l initialisation (méthode d initialisation) l héritage depuis la classe NSObject permet de faciliter l instanciation 45
quelques méthodes à connaître... +alloc (tout à zéro sauf isa) : méthode de classe permettant d obtenir une instance +alloc est recherchée dans la hiérarchie et en remontant... Les classes sont des objets il existe différentes formes de méthodes d allocation, mais pour la stratégie standard d allocation la règle est que leur nom commence par alloc 46
quelques méthodes à connaître... -init (méthode d initialisation) la règle d écriture indique que si plusieurs méthodes d initialisation existent leur nom doit commencer par init -initwithstring -initwithcolor 47
l idiome d instanciation est donc d obtenir un objet par la factory puis de l initialiser, soit : id o = [[Classe alloc] init]; 48
l écriture d une méthode d initialisation nécessite quelques précautions l idiome standard est : - (id)initwithbidule:(bidule)b { self = [super init]; // le cas tordu des singletons... if (!self) return nil; // do the job return self; } 49
la notion de constructeur en objective-c est différente de celle des autres langages un constructeur est une méthode de classe renvoyant une instance initialisée et dont le nom, par convention, est préfixé par celui de la classe... @interface CompteEnBanque -(id)compteenbanqueavecdepot:(int)somme; @end attention, une telle construction fournit normalement en objet en autorelease (voir plus loin) 50
La gestion mémoire la gestion mémoire en objective-c se décline de deux façon différentes : gestion explicite basée sur un comptage de référence Memory Management Programming Guide for Cocoa gestion implicité reposant sur un ramassemiettes (garbage collector) Garbage Collection Programming Guide 51
le compteur de référence peut être manipulé à travers les sélecteurs suivants : retain : qui incrémente le compteur d une unité dans le but de retenir l objet afin de l utiliser en toute tranquillité release : qui décrémente le compteur d une unité afin d exprimer le fait qu on souhaite ne plus utiliser l objet et le rendre; la méthode dealloc de l objet est automatiquement appelée si le compteur devient nul autorelease 52
pour utiliser correctement le compteur de référence la règle suivante doit être appliquée : tout responsable de l incrémentation du compteur doit en principe s occuper luimême de la décrémentation correspondante des incrémentations du compteur sont (normalement) automatiquement opérées par toute méthode ayant pour rôle d allouer un objet : alloc, copy, mutablecopy 53
autorelease? kesako? lorsque la règle précédente ne peut être appliquée, il faut utiliser autorelease par exemple dans une factory ou une variante autorelease est un release retardé : autorelease inscrit l objet dans la collection courante d objets à relâcher (autorelease pool), un objet de l autorelease pool recevra un message release lorsque le pool sera vidé (donc bien plus tard)... 54
L introspection disponible avec NSObject +(BOOL)instanceRespondToSelector:(SEL) -(BOOL)respondsToSelector:(SEL) -class -superclass -(BOOL)isKindOfClass:(Class) -(BOOL)isMemberOfClass:(Class) -(BOOL)conformsToProtocol:(Protocol) 55
l affichage à des fins de débogage s effectue habituellement à travers le mécanisme de traçage. La fonction à utiliser est : NSLog(NSString *format, ); dont le fonctionnement est identique à printf attention une constante littérale de NSString est préfixée par @, @ Bonjour est une NSString, Bonjour est un char * %@ est à utiliser dans NSLog pour «imprimer» un objet via les services : +(NSString *)description; -(NSString *)description; 56
Les propriétés les propriétés objective-c permettent de spécifier le comportement de certains attributs de la classe en particulier le comportement des accesseurs vis-à-vis de la valeur on doit : déclarer les propriétés implémenter les propriétés 57
la déclaration a la forme suivante : @property(attributs) type name; où les attributs peuvent être : readonly/readwrite pour définir les opérations valides sur la donnée (défaut readwrite) getter=gettername pour attribuer un nom au getter (par défaut celui de la propriété) setter=settername pour attribuer un nom au setter (par défaut celui de la propriété préfixé par set) assign/retain/copy/strong/weak afin de définir la sémantique vis-à-vis de la gestion mémoire (défaut assign) nonatomic pour indiquer qu il n est pas nécessaire d obtenir l atomicité des opérations 58
la définition ou l implémentation s effectue dans l implémentation de la classe : peut être réalisée «à la main» synthétisé avec : @synthesize [syntheticname=]name; si l implémentation sera fournie dynamiquement à l exécution il faut utiliser : @dynamic name; 59
@interface MaClasse { int valeur; } @property (readwrite) int value; @end @implementation MaClasse @synthesize valeur; @end MaClasse *unobjet = [[MaClasse alloc] init]; [unobjet setvaleur:20]; int v = [unobjet valeur]; 60
lorsque les getters/setters existent il est possible d utiliser la syntaxe pointée pour accéder à la donnée à travers les getters/ setters objet.valeur = unevaleur; fait appel au setter! unevaleur = objet.valeur; fait appel au getter! la notation -> ne fait pas appel aux getters/ setters (elle est donc à déconseiller) 61
KVC (Key-Value Coding) une implémentation du pattern Associative Storage / Associative Array les objets peuvent être vus comme un container associatif dans lequel les données d instances peuvent y être acceédées par leur nom (comme chaîne de caractères) [objet valueforkey:@ champ ]; [objet setvalue:valeur forkey:@ champ ]; KVC (Key-Value Coding) fonctionne sans effort si : les objets descendent de NSObject les getters et setters de l attribut existent 62
Quelques compléments 63
comparaison d objets : -(BOOL)isEqual:(id)objet; -(unsigned)hash; chargement : +(void)load; +(void)initialize; 64
énumerations rapides (fast enumeration) for (type var in expression) {...} type var; for (var in expression) {...} expression conforme au protocole NSFastEnumeration énumérations plus efficaces qu avec NSEnumerator syntaxe allégée énumération protégée contre les exceptions 65
sélection de message générique : -(id)performselector:(sel); «capture» de méthodes non existantes : -(void)forwardinvocation:(nsinvocation *) -(NSMethodSignature*)methodSignatureForSelector: (SEL)selector -(void)doesnotrecognizedselector:(sel) SEL unselecteur = @selector(toto); [unobjet performselector:unselecteur]; 66
performselector ne peut êter utilisé que pour des méthodes à zéro, un ou deux arguments si l on désire générer un appel à une méthode quelconque il faut utiliser NSInvocation on dispose des fonctions utilitaires suivantes : const char* sel_getname(sel aselector); SEL sel_getuid(const char *str); 67