Obiectiv-C

De la Wikipedia, enciclopedia liberă.
Salt la navigare Salt la căutare
Obiectiv-C
limbaj de programare
Autor Brad Cox si Tom Dragoste ( StepStone Corp. )
Data de origine 1983
Ultima versiune 2.0
Utilizare limbaj de uz general
Paradigme programare orientată obiect
Tastare slab , dinamic
Extensii comune h, m, mm și C
Influențată de C , Smalltalk
A influențat C ++ , Swift , Java
Implementare referință
Sistem de operare Multiplatform
Site-ul web developer.apple.com/library/mac/navigation/

Obiectiv-C, de multe ori , de asemenea , menționată ca obiectiv C sau objc sau objc, este un limbaj de programare reflectiv orientat pe obiect , dezvoltat de Brad Cox la mijlocul anilor optzeci de ani de la StepStone Corporation.

După cum sugerează și numele, obiectivul C este un obiect extensie a limbajului C . Se păstrează compatibilitatea totală cu C (spre deosebire de ceea ce se întâmplă, de exemplu, în cazul C ++ ). Printre alte lucruri, de asemenea , din cauza acestei compatibilitate, Objective C nu este echipat cu tastarea puternică (caracteristică că , în loc să prezinte, printre altele, este faptul că C ++ Java ).

Extensiile pe obiecte pentru a Objective C îmbogățește modelul semantic al limbajului C sunt inspirate de Smalltalk , în special gestionarea mesajului . Caracteristicile sistemului de rulare plasat obiectivul C între limbi pentru obiectele dinamice. Toate elementele clasice ale programării orientate pe obiecte sunt sprijinite; dar există concepte inovatoare pe acest front, ca mecanismul de categoriile și a instrumentelor legate de reflecție .

Popularitatea sa se datorează în principal cadrului OpenStep al NeXT și succesorul său de cacao , prezent în sistemul de operare MacOS de la Apple . Un NeXT a fost responsabil pentru susținerea în obiectivul C compilator gcc de GNU .

Istorie

Originile

La începutul anilor optzeci , practica comună de " inginerie software sa bazat pe programare structurată . Acest mod a fost dezvoltat pentru a fi în măsură să împartă programe mari în bucăți mai mici, în principal, pentru a facilita dezvoltarea de software și lucrări de întreținere. Cu toate acestea, odată cu creșterea amplorii problemelor care trebuie rezolvate, programarea structurată a devenit mai puțin și mai puțin utile, din moment ce a condus la elaborarea unui număr tot mai mare de proceduri, un cod de spaghete și puțin reutilizarea codului sursă .

Acesta a fost apoi emis ipoteza că programarea orientată pe obiect ar putea fi o posibilă soluție la această problemă. De fapt, Smalltalk au abordat deja multe dintre aceste probleme de inginerie, în ciuda dezavantajul de a necesita o mașină virtuală care a jucat un obiect în memorie numită imagine care conține toate instrumentele necesare. Imaginea Smalltalk a fost foarte mare, acesta tinde să fie folosită o cantitate enormă de memorie pentru epoca și , de asemenea , a fugit foarte încet din cauza lipsei unui anumit suport de " hardware pentru mașini virtuale.

Obiectivul de C a fost creat în primul rând de Brad Cox si Tom Dragoste la începutul anilor optzeci la StepStone . Ambele au fost introduse în Smalltalk , în timpul șederii lor la Centrul de programare Tehnologia de ITT Corporation în 1981 . Cox a început să devină interesați de problemele legate de posibilitatea de reutilizare a software - ului și a realizat că o limbă ca Smalltalk ar fi fost extrem de valoros pentru construirea de puternic mediu de dezvoltare pentru designeri la ITT. Cox a inceput modificarea compilatorul C pentru a adăuga unele dintre caracteristicile lui Smalltalk. El a primit bine în curând o punere în aplicare de lucru de o extensie a limbajului C , obiectele numite OOPC (orientat pe obiect de programare în C). Între timp Dragostea a fost angajat de către Schlumberger Research în 1982 și au avut posibilitatea de a dobândi prima copie comercială a Smalltalk-80, care a influențat mai târziu dezvoltarea copilului lor.

Pentru a arăta că limba a fost un progres real, Cox a arătat că puține adaptări practice la instrumentele existente au fost necesare pentru a face componente software interschimbabile. Mai exact, a fost necesar pentru a sprijini într - un obiect flexibil , cu un set de biblioteci software care au fost ușor de utilizat și ar permite codul sursă (și toate resursele necesare pentru codul) care urmează să fie colectate într - un singur format de platformă .

Cox și dragoste format în cele din urmă o nouă companie , Productivity Products International (PPI), pentru a comercializa produsul lor , care ar tânăr un compilator C Obiectiv cu un puternic biblioteci de clase.

In 1986 Cox a publicat descrierea lui Obiectiv C în forma sa originală în programarea orientată pe obiecte de carte, o abordare evolutiva. Deși el a fost atent să sublinieze că problema a software - ului posibilitatea de reutilizare nu ar putea fi epuizate de limbajul de programare , Objective C este adesea dovedit a fi comparate, caracteristica pentru caracteristica, cu alte limbi.

Următorul

În 1988 , NeXT , compania fondată de Steve Jobs după Apple a , a obținut o licență de la obiectivul C StepStone (atunci proprietar al mărcii ) și a creat propriul lor compilator C Obiectiv și biblioteci , cum ar fi bazate pe " interfața cu utilizatorul de NeXTStep . Deși stația de lucru NeXTStep nu a reușit să aibă un impact major asupra pieței, instrumentele lor au fost foarte apreciate de către sectorul industrial. Acest lucru a condus NeXT să renunțe la producția de instrumente hardware și software să se concentreze pe vânzarea NeXTStep (și OpenStep ) ca platformă pentru programare.

Apoi Proiectul GNU a început să lucreze pe clona gratuit numit GNUstep , bazat pe standardul OpenStep. Dennis Glatting a scris primul run-time gnu-objc în 1992 și Richard Stallman , urmat la scurt timp după de o secundă. Run-time GNU Objective C, care este folosit din 1993 , a fost dezvoltat de Kresten Krab Thorup , când a fost un student în Danemarca .

măr

După achiziționarea NeXT în 1996 , Apple a folosit OpenStep ca bază pentru noile sale sistem de operare MacOS . Acest lucru a permis să includă obiectivul C NeXT și sistemul său de dezvoltare de proiect Builder (redenumit mai târziu Xcode ). Cele mai multe curente API - uri Apple ( Cocoa API ) se bazează pe OpenStep obiecte de interfață și reprezintă cel mai important mediu de dezvoltare bazat pe obiectivul C utilizate în prezent.

Dezvoltări

Azi

Astăzi , obiectivul C este adesea utilizat în tandem cu bibliotecile fixe de obiecte standard (denumite adesea „“ sau „kit - cadru “) ca cacao și GNUstep . Aceste biblioteci sunt adesea expediate împreună cu sistemul de operare : bibliotecile GNUstep fac parte din colecția de software GNU și , uneori , prezente în unele distribuții GNU / Linux și cacao MacOS . Programatorul nu este obligat să moștenească funcționalitatea clasei de bază existente (NSObject). Obiectiv C permite declararea unor noi clase de bază, care nu moștenesc niciuna dintre funcțiile de pre-existente. Inițial programare medii bazate pe Objective C a oferit clasa Object cu unele caracteristici de bază, dar cu introducerea de OpenStep , NeXT a creat o nouă clasă de bază numită NSObject , care a oferit caracteristici suplimentare în afară de cele de obiect. Aproape toate clasele de cacao moștenesc de la NSObject.

Redenumirea nu este numai a servit pentru a diferenția noile clase de comportament în noul cadru, dar a permis codul încă folosind clasa Object să coexiste (deși cu unele limitări) în același sistem de execuție . În același timp, introducerea prefixului două litere a devenit un fel de surogat pentru lipsa de spacename (sau spațiile de nume, dacă preferați) în Obiectiv C. Folosind un prefix pentru a crea un pachet informal de identificare a devenit o practică standard în comunitatea de programare C Obiectiv.

Obiectiv C 2.0

La Developers Conference la nivel mondial din 2006 , Apple a anunțat lansarea „Obiectiv C 2.0“ , al cărui conținut sunt de colectare a gunoiului , îmbunătățiri în sintaxa [1] , dintre îmbunătățirile run-time de performanță [2] și de sprijin pentru a 64- biți [3 ] . Nu se cunoaște încă atunci când aceste evoluții vor fi susținute în GNU run-time, deși acestea sunt deja în Mac OS X Leopard [4] .

De colectare a gunoiului

Obiectiv C 2.0 permite colectarea gunoiului , dar într - un mod dependent de sistemul de operare. Cu toate acestea, puteți utiliza într - un mod invers compatibil, astfel încât codul sursă scris pentru versiunile anterioare continua să funcționeze.

Proprietate

In timp ce anterior variabilele exemplu necesită metode explicite de citire și scriere (numite getters și setteri), C Obiectiv 2.0 prezintă proprietăți (proprietate) cu următoarea sintaxă:

 @interface Persoana: NSObject {
 }
 @property (readonly) NSString * nume;
 @property (readonly) int vârstă;
 - (id) initWithName :( NSString) Nume :( vârsta int) vârstă;
 @Sfârșit

După ce a intrat în interfața, proprietățile pot fi accesate folosind notația descrisă în exemplul:

 NSString nume * = unaPersona. nume ;

Compilatorul traduce această notație în apeluri metoda de accesorii. Instrucțiunea anterioară este echivalentă cu:

 NSString name * = [nume unaPersona];

enumerare rapidă

In loc de a folosi un obiect recenzor pentru a itera printr-o colecție de obiecte, Obiectiv C 2.0 ofertă o sintaxă buclă dedicat; luând în sus exemplul anterior:

 pentru (persoană * persoană în agentul)
  NSLog (@ "% @% are ani.", Nume de persoană, persoana Eta..);

Compiler obiect portabil

În plus față de CCG / NeXT / implementările la Apple , care au adăugat mai multe extensii în original , cel StepStone , există un alt Open Source implementarea obiectivului C , care adaugă un set ușor diferit de extensii: obiectului portabil compilatorului [1] pune în aplicare între mai multe de asemenea, unele blocuri de cod pe stilul Smalltalk.

Sintaxă

Objective-C este un strat subțire plasat deasupra limbajului C ; Apoi , C este un subset îngust Obiectiv C. Rezultă că este posibil să compileze orice program scris în C , cu un compilator C Obiectiv O mare parte din sintaxa (clauzele preprocesor , expresii , declarații și apeluri de funcții ) este derivată din cea a C , în timp ce sintaxa referitoare la caracteristicile orientate pe obiect a fost creat pentru a obține comunicarea mesajelor de schimb similare cu Smalltalk .

Mesaje

Sintaxa adăugată în ceea ce privește C este destinată să sprijine programarea orientată pe obiecte. Modelul de programare a Obiectivului C se bazează pe schimbul de mesaje între obiecte precum și în Smalltalk . Acest model este diferit de cel al Simula , care este folosit în mai multe limbi , cum ar fi, printre altele, C ++ . Această distincție este semantically importantă și constă în principal în faptul că , în obiectivul C nu este numit o metodă , dar trimite un mesaj .

Se spune că un obiect numit Ogg a cărui clasă implementează metoda faiQualcosa răspunde la mesajul faiQualcosa. Trimiterea mesajului obiect faiQualcosa ogg este exprimat prin:

 [Ogg faiQualcosa];

în timp ce acțiunea echivalentă în C ++ și Java ar fi exprimat prin:

 ogg. faiQualcosa ();

În acest fel , puteți trimite mesaje de la un obiect , chiar dacă obiectul nu este în măsură să răspundă. Aceasta diferă de limbajul tastat static ca C ++ și Java , în care toate apelurile trebuie să fie metode de pre-definite.

Interfețe și implementări

-Obiectiv C impune ca „ interfața și“ punerea în aplicare a unei clase sunt declarate, în diferite blocuri de cod. Prin convenție, interfața este pus într-un fișier cu „.h“ sufixul, în timp ce punerea în aplicare într-un fișier cu „.m“ sufixul.

Interfață

Interfața unei clase este de obicei definit într-un fișier „.h“. Convenția de utilizat este de a denumi fișierul bazat pe numele clasei, în exemplul „NomeDellaClasse.h“.

 // definiție interfață: "ClassName.h"

 #import "NameOfSuperclass.h"

 @interface NomeDellaClasse: NomeDellaSuperclasse
 {
    // variabile de instanta
    int variabileIntera;
    float variabileFloat;
    ...
 }
 // metodele clasei
 + metodoDiClasse1
 + metodoDiClasse2
 + ...

 // metode instanță
 - metodoDiIstanza1
 - metodoDiIstanza2
 - ...

 @Sfârșit

Semnul minus (-) reprezintă metodele exemplu, în timp ce semnul plus (+) clasa (analog cu functiile statice ale C ++). Observați diferența în sensul cu convențiile de diagrame UML în cazul în care cele două mărci care reprezintă , respectiv , metodele private și publice.

Implementare

Interfața declară doar prototipuri ale metodelor și nu aceleași metode care sunt incluse în punerea în aplicare. Punerea în aplicare este de obicei scrisă într-un fișier cu „.m“ extensia. Convenția de utilizat este de a denumi fișierul bazat pe numele clasei, în exemplul „NomeDellaClasse.m“

 // implementare definiție: "ClassName.m"

 #import "ClassName.h"

 @implementation NomeDellaClasse
 + metodoDiClasse1
 {
    // implementare
    ...
 }
  + metodoDiClasse2
 {
    // implementare
    ...
 }
 ...
 - metodoDiIstanza1
 {
    // implementare
    ...
 }
 - metodoDiIstanza2
 {
    // implementare
    ...
 }
 ...

 @Sfârșit

Metodele sunt scrise într - un alt mod de funcțiile în stil exemplu C. Pentru, o funcție, în ambele C și în Obiectiv C urmează următoarea formă generală:

 fai_la_radice_quadrata int (int i)
 {
    retur radice_quadrata (i);
 }

care va avea ca prototip:

 fai_la_radice_quadrata int (int);

Punerea în aplicare ca metodă va deveni:

 - (int) fai_la_radice_quadrata :( int) i
 {
    întoarcere [auto radice_quadrata: i];
 }

O abordare mai canonică a scris metoda ar fi de a cita primul argument în numele selectorului:

 - (int) faiLaRadiceQuadrataDiInt: (int) i
 {
    întoarcere [auto radiceQuadrataDiInt: i];
 }

Această sintaxă poate arata complicat, dar vă permite să atribuiți nume parametri , cum ar fi:

 - (int) changeColorWithRed :( int) r verde :( int) g albastru :( int) b

pot fi invocate ca aceasta:

 [MyColor changeColorWithRed: 5 verde: albastru 2: 6];

Reprezentările interne ale acestor metode pot varia cu diferite implementari ale Obiectiv C.

Dacă MyColor, în exemplul anterior, a fost clasa de culoare, în interior metoda exemplu -changeColorWithRed: verde: albastru: ar putea fi etichetat _i_Color_changeColorWithRed_green_blue, unde urmată de numele clasei, se referă la faptul că aceasta este o metodă de instanță și colon (: ) se înlocuiesc cu o subliniere (_). Deoarece ordinea parametrilor este parte din numele metodei, aceasta nu poate fi schimbată.

În orice caz, numele interne ale funcțiilor sunt utilizate rareori trimise mesaje în mod direct și , de asemenea , în general , sunt convertite în funcții definite în biblioteca run-time , și nu avea acces direct numele interne. Acest lucru se datorează și faptului că , la momentul de compilare nu știu întotdeauna ce metodă va fi numit de fapt, pentru că clasa destinatarului (obiectul la care este trimis mesajul) poate fi necunoscut până la momentul execuției.

Protocoale

Obiectivul C a fost extins de la NeXT pentru a introduce conceptul de moștenire multiplă a specifice, dar nu și de punere în aplicare, prin utilizarea de protocoale. Acesta este un model care poate fi obținută atât printr - o formă de moștenire multiplă dintr - o clasă abstractă (ca in C ++) și (ca mai frecvent in Java sau C # ) , prin utilizarea unei interfețe (chiar și în C ++ există interfețe, de asemenea , în cazul în care nu există nici un cuvânt cheie în mod explicit să le declare). Obiectiv C face uz de ambele protocoale, numite protocoale informale și protocoale impuse de spus protocoale formale compilator.

Un protocol informal este o listă de metode care pot fi puse în aplicare de o clasă. Este specificat în documentație, deoarece nu este explicit prezent în limba. Protocoale informale includ adesea metode opționale, în cazul în care punerea în aplicare a metodei se poate schimba comportamentul clasei. De exemplu, o clasă cu un câmp de text ar putea avea un „delegat“ ar trebui să pună în aplicare un protocol informal cu o metodă opțională de auto . Descoper câmpului de text în cazul în care implementează delegatul sau mai puțin metoda (prin mecanismul de reflexie ), și, în caz pozitiv, se solicită sprijin pentru completarea automată.

Un protocol oficial este similar cu o interfață # Java sau C. Acesta constă dintr-o listă de metode pe care fiecare clasă poate pretinde să pună în aplicare. Compilatorul va raporta o eroare în cazul în care clasa nu implementează toate metodele din protocoalele care declară. Conceptul C, obiectivul de a protocoalelor diferă de cel din Java și C # interfețe în faptul că o clasă poate implementa un protocol fără explicit declarându-l. Diferența nu este perceptibil în afara codului. protocoale formale nu poate oferi orice punere în aplicare, ei pur și simplu asigura că apelanții clase care sunt conforme cu protocolul va oferi implementari. În bibliotecile NeXT / Apple a , protocoale sunt utilizate în mod frecvent de către sistem pentru obiecte distribuite pentru a reprezenta capacitățile unui obiect care rulează pe un sistem la distanță.

Sintaxa

 blocarea @protocol
 - (void) de blocare;
 - deblocare (void);
 @Sfârșit

Aceasta indică faptul că există o idee abstractă de blocare care poate fi utilizat; atunci când este declarat într-o definiție de clasă

 @interface ClassName: NomeSuperClasse <Locking>
 @Sfârșit

Aceasta indică faptul că instanțele ClassName oferă o punere în aplicare pentru cele două metode de exemplu , așa cum doresc. Această specificație abstractă este deosebit de util pentru a descrie comportamentul dorit , de exemplu , de plugin - ul fără a pune nici o limitare asupra a ceea ce ar trebui să fie ierarhia de punere în aplicare.

dactilografiere dinamică

Obiectiv C (cum ar fi Smalltalk) pot folosi tastarea dinamic ; adică, face posibilă, pentru a crește flexibilitatea, pentru a trimite un obiect un mesaj care nu este definit în interfața sa. În Obiectiv C, un obiect poate „captura“ acest mesaj și poate trimite-l la un alt obiect (care poate răspunde corect sau la rândul său, trimite mesajul la un alt obiect și așa mai departe). Acest comportament se numește redirecționare (în limba italiană : redirecționare) sau proxy a mesajului (vezi mai jos ). Alternativ, puteți utiliza un handler de eroare în cazul în care mesajul nu poate fi transmis. În cazul în care obiectul nu transmite mesajul, nu se ocupa cu eroarea sau nu răspunde, o eroare va fi generată în timpul rulării.

Informații dactilografiere statice pot fi adăugate opțional la variabilele. Astfel de informații se verifică în momentul compilarii . În instrucțiunile următoare, este furnizat mai multe și mai multe informații specifice. Situațiile sunt echivalente în timpul execuției, dar informația permite compilatorului să avertizeze programator dacă argumentele trecut nu se potrivesc cu tipurile specificate. În prima declarație, obiectul trebuie să respecte protocolul aProtocol și, în al doilea, trebuie să fie un membru al clasei NSNumber.

- setMyValue: (id <aProtocol>) foo;
- setMyValue: (NSNumber *) foo;

dactilografiere dinamic poate fi o caracteristică foarte puternic. Dacă implementați clase container folosind limbaje , cum ar fi tastate static Java (înainte de versiunea 1.5), programator este forțat să scrie clase container pentru obiect generic și apoi utilizați conversia de tip pentru a se adapta la anumite obiecte; această conversie, cu toate acestea, contrazice disciplina semantică a dactilografiere statice.

Redirecționarea

Deoarece obiectivul C permite un mesaj pentru a fi trimis la un obiect care nu poate răspunde la ea, obiectul se poate ocupa acel mesaj în alte moduri. Una dintre acestea ar putea fi în opinia sa (în limba engleză : redirecționarea) într - un alt obiect care este în măsură să răspundă. Redirecționarea poate fi folosit pentru a pune în aplicare pur și simplu unele modele de design , cum ar fi Observer model sau modelul Proxy .

Sistemul de Object rulare Obiectiv C specifică o serie de metode de clasa Object

  • Metode de expediere:
 - (retval_t) transmite: (SEL) sel: (arglist_t) args; // cu GCC
- (id) transmite: (SEL) sel: (marg_list) args; // cu sisteme de NeXT / Apple
  • metode de acțiune:
 - (retval_t) performv: (SEL) sel: (arglist_t) args; // cu GCC
- (id) performv: (SEL) sel: (marg_list) args; // cu sisteme de NeXT / Apple

și dacă un obiect dorește să pună în aplicare transmiterea necesită doar „ suprascriere “ metode forwardarea pentru a defini comportamentul lor. Metodele de acțiune performv:: nu necesită suprascriere.

Exemplu

Aici este un program de exemplu care ilustrează fundamentele de expediere.

Forwarder.h
 #import <objc / Object.h>
 
 @interface transportor: Obiect
 {
    destinatar id; // Obiectul dorim să transmită mesajul
 }
 
 // Metode accesorii
 - (id) destinatar;
 - (void) SetRecipient :( id) _recipient; 
 
 @Sfârșit
Forwarder.m
 #import "Forwarder.h"
 
 @implementation transportor
 
 - înainte: (SEL) sel: (marg_list) args
 {
    / *
* Verificați dacă destinatarul răspunde de fapt la mesaj.
* Acest lucru poate sau nu poate fi de dorit, de exemplu, în cazul în care un destinatar
* Nu răspunde la mesaj, el poate transmite mesajul însuși.
* /
    if ([destinatar respondsTo: sel]) 
       retur [performv destinatar: individual: args];
    altceva
       întoarcere [eroare de sine: „destinatarul nu răspunde“];
 }
 
 - (id) SetRecipient: (id) _recipient
 {
    destinatar = _recipient;
    întoarce de sine;
 }
 
 - (id) destinatar
 {
    reveni destinatar;
 }
 @Sfârșit
Recipient.h
 #import <objc / Object.h>
 
 // Un obiect destinatar simplu.
 @interface Destinatar: Obiect
 - (id) salut;
 @Sfârșit
Recipient.m
 #import "Recipient.h"
 
 @implementation Destinatar
 
 - (id) Hello
 {
    printf ( "Beneficiarul vă salut \ n!");
 
    întoarce de sine;
 }
 
 @Sfârșit
main.m
 #import "Forwarder.h"
 #import "Recipient.h"
 
 int
 main (void)
 {
    Transportor expeditor * = [transportor nou];
    * Destinatar destinatar = [Destinatar nou];
 
    [Transportor SetRecipient: destinatar]; // Setați destinatarul
    / *
* Rețineți că „expeditor“ nu răspunde la mesaj!
* Acesta va fi transmis. Toate metodele nerecunoscute vor fi
* Transmis la destinatar ( în cazul în care beneficiarul le administrează,
* După cum se menționează în „transportor“).
* /
    [Transportor salut]; 
 
    retur 0 ;
 }

Notă

Dacă ar fi să compila exemplul, compilatorul va raporta

 $ GCC -x obiectiv-c--Wno import Forwarder.m Recipient.m main.m -lobjc
main.m: În funcție de `principală„:
main.m: 12: avertisment: `transportor„nu răspunde la` salut“
$

Rapoartele compilatorul ceea ce a fost explicat mai înainte, ca Forwarder nu răspunde la mesaj. În unele cazuri, acest indicator poate ajuta la erori de găsit, dar în acest caz, acesta poate fi ignorat, deoarece redirecționarea a fost pus în aplicare. Pentru a rula programul va fi suficient:

 $ ./a.out
Destinatar spune salut!

Categorii

Experiența lumii de programare structurată a demonstrat că o modalitate de a îmbunătăți structura codului sursă este să - l rupe în bucăți mai mici. Pentru a îmbunătăți acest proces Objective C a introdus conceptul de clasă.

Categoriile vă permit să adăugați metode la o clasă separată. Programatorul poate pune grupuri de metode înrudite într-o categorie pentru a le face mai ușor de citit. De exemplu, puteți crea o categorie ControlloOrtografico „pe“ un obiect de tip string pentru a aduna într - un singur loc toate metodele de ortografie.

În plus, metodele incluse într - o categorie sunt adăugate la clasa la rulare . În acest fel, categoriile permit programatorului să adăugați metode la o clasă existente, fără a fi nevoie de recompilare și fără a fi nevoie de a avea codul sursă al acestuia. În exemplu, în cazul în care sistemul nu prevede verificarea ortografiei sprijin în punerea în aplicare a clasei String, o puteți adăuga, fără a schimba sursa acesteia.

Metodele plasate în categorii fac parte, practic, din clasa atunci când programul se execută. O categorie accesează, de asemenea, toate variabilele de instanță ale clasei, chiar și cele private.

Categoriile oferă o soluție pentru „fragilitatea claselor de bază“ probleme în ceea ce privește metodele.

Dacă declarați o metodă într - o clasă cu același nume ca și o metodă existentă într - o clasă, se adoptă metoda clasei. În acest fel, categorii nu se pot adăuga numai metode la clase, dar poate înlocui, de asemenea, metodele existente. Această caracteristică poate fi utilizată pentru a repara erorile din alte clase, pur și simplu prin rescrierea metodele lor, sau pentru a modifica comportamentul unei clase într-un anumit program. Dacă cele două categorii au metode cu aceeași semnătură, nu este definit ce metodă va executa efectiv.

Diferite limbi au încercat să adăugați această funcție în diferite moduri. Limba TOM a adus mai in fata conceptul in timp ce , de asemenea , permițându - vă să adăugați variabile. Alte limbi, cum ar fi Sinele , au soluții orientate în schimb adoptate prototipuri ,

Exemplu

Acest exemplu construiește o clasa Integer , definind mai întâi o clasă de bază cu doar câteva metode puse în aplicare și apoi adăugarea a două categorii, Arithmetic și de Display , care se extind clasa de bază. In timp ce aceste categorii pot avea acces la variabilele private ale clasei de bază, este o practică bună de a accesa aceste variabile, prin metode de servicii care ajuta la menținerea categoriilor cât mai independentă a claselor care se extind. Acesta este un caz tipic de utilizare a categoriilor pentru a adăuga sau a modifica anumite metode ale clasei de bază (deși nu este considerată o bună practică de a utiliza categorii pentru a trece peste subclase).

Integer.h
 #include <objc / Object.h>
 
@interface Integer: Obiect
{
   integer int;
}

- (int) întreg;
- (id) Integer: (int) _Integer;
@Sfârșit
Integer.m
 #import "Integer.h"

integer @implementation
- (int) întreg
{
   întoarce întreg;
}

- (id) Integer: (int) _Integer
{
   _Integer = număr întreg;
   întoarce de sine;
}
@Sfârșit
Arithmetic.h
 #import "Integer.h"

@interface Integer (aritmetică)
- (id) se adaugă: (Integer *) completare de ;
- (id) sub: (Integer *) Scăzător;
@Sfârșit
Arithmetic.m
 #import "Arithmetic.h"

@implementation Integer (aritmetică) 
- (id) se adaugă: (Integer *) completare de
{
   întoarcere [sine întreg: [auto întreg] + [număr întreg completare de ]];
}

- (id) sub: (Integer *) Scăzător
{
   întoarcere [sine întreg: [auto întreg] - [descăzut întreg]];
}
@Sfârșit
Display.h
 #import "Integer.h"

@interface Integer (display)
- (id) showstars;
- (id) showint;
@Sfârșit
Display.m
 #import "Display.h"

@implementation Integer (display) 
- (id) showstars
{
   int i, x = [auto întreg];
   pentru (i = 0; i <x; i ++)
      printf ( "*");
   printf ( "\ n");

   întoarce de sine;
}

- (id) showint
{
   printf ( "% d \ n", [auto întreg]);

   întoarce de sine;
}
@Sfârșit
main.m
 #import "Integer.h"
#import "Arithmetic.h"
#import "Display.h"

int main ( nul )
{
   Integer * num1 = [new Integer], * num2 = [new Integer];
   int x;
   printf ( "Introduceți un întreg:");
   scanf ( "% d", & x);
   [Integer number1: x];
   [Showstars num1];
   printf ( "Introduceți un întreg:");
   scanf ( "% d", & x);
   [Integer num2: x];
   [Showstars num2];

   [Adauga NUM1: num2];
   [Num1 showint];
}

Notă

compilarea se face după cum urmează:

 GCC -x obiectiv-c main.m Integer.m Arithmetic.m Display.m -lobjc

Si può provare ad omettere le linee #import "Arithmetic.h" e [num1 add:num2] e ad omettere Arithmetic.m in compilazione. Il programma girerà lo stesso. Ciò significa che è possibile aggiungere o togliere categorie, dato che se non si ha bisogno di una certa funzionalità offerta da una categoria, basta semplicemente escluderla dalla compilazione.

Posing

Objective C permette ad una classe di sostituirne completamente un'altra; questo meccanismo è detto posing (dall' inglese pose as : fingersi per qualcun altro). La classe sostituita è chiamata classe target e la classe che sostituisce è chiamata classe posing . Tutti i messaggi inviati alla classe target vengono ricevuti in sua vece dalla classe posing. Esistono numerose restrizioni da rispettare per effettuare il posing:

  • Una classe può solo sostituirsi a una delle sue superclassi dirette o indirette.
  • La classe posing non deve definire nessuna nuova variabile d'istanza che sia assente dalla classe target (anche se può definire o sovrascrivere metodi).
  • Nessun messaggio deve essere inviato alla classe target prima del posing

Il posing, similmente alle categorie, consente un aumento globale delle classi esistenti e permette due possibilità assenti nelle categorie:

  • Una classe posing può chiamare metodi sovrascritti attraverso super , incorporando così l'implementazione della classe target.
  • Una classe posing può sovrascrivere i metodi definiti nelle categorie.

Ad esempio:

 @interface CustomNSApplication : NSApplication
 @end
 
 @implementation CustomNSApplication
 - ( void ) setMainMenu : ( NSMenu * ) menu
 {
     // fa qualcosa col menu
 }
 @end
 
 class_poseAs ([ CustomNSApplication class ], [ NSApplication class ]);

Questo intercetta ogni invocazione a setMainMenu di NSApplication.

Il posing è stato dichiarato deprecato con Mac OS X Leopard e non è disponibile nei run-time a 64 bit.

#import

In C, la direttiva del precompilatore #include consente di inserire un intero file prima dell'inizio effettivo della compilazione . Objective-C aggiunge a questa la direttiva #import , che oltre a svolgere lo stesso ruolo della precedente, evita di includere il file qualora sia già stato incluso in precedenza.

Ad esempio, il file A include i file X e Y, ma X e Y includono ciascuno il file Q, in questo caso Q verrebbe incluso due volte nel file risultante causando così delle definizioni duplicate e quindi un errore in compilazione. Se il file Q venisse incluso con la direttiva #import , solo la prima inclusione verrebbe effettivamente effettuata e tutte le successive verrebbero ignorate.

Alcuni compilatori, compreso GCC , supportano la clausola #import anche per il linguaggio C; il suo uso viene comunque scoraggiato sulla base del fatto che l'utilizzatore dei file da includere dovrebbe distinguere quali file includere solo una volta da quelli progettati per essere inclusi più volte. Questo onere dovrebbe in teoria essere a carico dell'implementatore del file da includere che può usare la direttiva #pragma once o usare la tradizionale tecnica :

 #ifndef H_PERSONA
#define H_PERSONA
// ... contenuto di header.h ...
#endif

In questo caso le direttive #include e #import diventano equivalenti.

Altre caratteristiche

Objective C ha incluso sin dal suo apparire un lista di caratteristiche che sono tuttora in via di acquisizione in altri linguaggi, oltre ad alcune che sono rimaste sue uniche prerogative. Ciò ha permesso di mettere in luce, partendo dalla realizzazione di Cox (ed in seguito da quella di NeXT ), che alcuni considerazioni superano i concetti più strettamente legati al linguaggio. Il sistema deve essere usabile e flessibile nel complesso per poter essere pienamente fruibile.

  • Delegare i metodi ad altri oggetti al run-time è banale. Basta semplicemente aggiungere una categoria comprendente le modifiche ad un metodo per implementare il forwarding al destinatario della delega.
  • La chiamata di procedura remota è banale. Basta semplicemente aggiungere una categoria con un metodo che " serializzi " l'invocazione e la inoltri.
  • Lo swizzling dei puntatori consente di modificare le classi al run-time. Tipicamente per scopi di debugging se un oggetto la cui memoria è stata rilasciata dovesse venire referenziato per errore.
  • Un oggetto può essere archiviato su uno stream (ad esempio un file ) e può essere riletto e recuperato su richiesta.

Objective C++

Objective C++ è un front-end del compilatore gcc in grado di compilare codice sorgente che usa una sintassi combinazione di C++ e Objective C. Objective C++ aggiunge a C++ le stesse estensioni che Objective C aggiunge a C. Dato che nulla è stato fatto per unificare le differenze semantiche tra i due linguaggi, sono state applicate alcune restrizioni:

  • una classe C++ non può derivare da una classe Objective C e viceversa
  • i namespace C++ non possono essere dichiarati all'interno di una dichiarazione Objective C
  • le classi Objective C non possono contenere variabili di istanza di classi C++ che non abbiano un costruttore di default o che abbiano uno o più metodi virtuali , ma si possono usare puntatori ad oggetti C++ come variabili di istanza senza restrizioni
  • la semantica "per valore" del C++ non può essere applicata agli oggetti Objective C, i quali rimangono accessibili solo mediante puntatori
  • non ci possono essere dichiarazioni Objective C in dichiarazioni di template C++ e viceversa. Comunque è possibile usare tipi Objective C (es. Nomeclasse *) come parametri di template C++
  • La gestione delle eccezioni Objective C è distinta da quella di C++

Analisi del linguaggio

L'implementazione dell'Objective C usa un semplice run-time system scritto in linguaggio C che aumenta di poco la dimensione delle applicazioni. Al contrario, la maggior parte dei sistemi object-oriented esistenti quando fu creato (e Java tuttora) usava una grossa macchina virtuale invasiva per l'intero sistema. I programmi scritti in Objective C tendono ad essere di poco più grandi delle dimensioni del loro codice oggetto e delle librerie usate (che generalmente non devono essere incluse nel codice distribuito), al contrario ad esempio dei sistemi Smalltalk dove grandi quantità di memoria sono necessarie semplicemente per aprire una finestra .

Il linguaggio può essere implementato con un compilatore C (in GCC , prima come un preprocessore ed in seguito come un modulo del compilatore) piuttosto che con un nuovo compilatore. Ciò consente all'Objective C di sfruttare l'enorme mole di codice, librerie e strumenti già esistenti in C che può essere adattata in Objective C per fornire un'interfaccia object-oriented. Tutte questi fattori riducono le barriere d'ingresso al nuovo linguaggio, fattore che costituì il problema principale di Smalltalk negli anni ottanta .

Le prime versioni di Objective C non supportavano la garbage collection . Al tempo questa scelta fu oggetto di discussioni e in molti (ai tempi di Smalltalk) la consideravano un lungo "tempo morto" in cui il sistema era reso non più utilizzabile. Anche se qualche implementazione di terze parti (principalmente GNUstep ) aveva già aggiunto questa caratteristica, è stata implementata da Apple una tecnica simile tramite ARC in Mac OS X Leopard , ma non è disponibile per applicazioni implementate per versioni precedenti del sistema operativo . [5]

Un'altra critica comunemente fatta all'Objective C è quella di non avere un supporto nativo per i namespace . I programmatori sono perciò costretti ad aggiungere prefissi in maniera più o meno arbitraria ai nomi delle classi che implementano, fatto che può causare collisioni. Dal 2007 tutte le classi e le funzioni di macOS in ambiente Cocoa hanno il prefisso "NS" (es. NSObject o NSButton ) per identificarle chiaramente; "NS" deriva dal nome delle classi definite durante lo sviluppo di NeXTSTEP .

Dato che Objective C è uno stretto superinsieme del C, non tratta i tipi primitivi del C come first-class object .

A differenza del C++, Objective C non supporta l' overloading degli operatori, consente l' ereditarietà solo diretta da una singola classe (vietando così l' ereditarietà multipla ). Dato che il linguaggio Java venne influenzato dall'Objective C, la decisione di usare l'ereditarietà singola venne portata anche in Java. In alternativa all'ereditarietà multipla possono essere usate le categorie ed i protocolli .

Differenze filosofiche tra Objective C e C++

Il progetto e l'implementazione del C++ e dell'Objective C rappresentano due diversi approcci all'estensione del C.

Oltre alla programmazione strutturata del C, C++ supporta direttamente la programmazione ad oggetti , la programmazione generica e la metaprogrammazione . C++ è inoltre corredato di una estesa libreria standard che include numerose classi container . L'Objective C, invece, aggiunge solo delle caratteristiche object-oriented al C; esso, nella sua versione più "pura" non offre lo stesso in termini di librerie standard, ma in molti contesti dove viene usato, viene corredato di una libreria sul modello di quella di OpenStep , di Cocoa o di GNUstep le quali forniscono funzionalità simili a quelle offerte dalla libreria standard di C++.

Un'altra notevole differenza consiste nel fatto che l'Objective C fornisce un maggior supporto run-time alla riflessione rispetto a C++. In Objective C si può interrogare un oggetto riguardo alle sue stesse proprietà, ad esempio se possa o meno rispondere ad un dato messaggio, mentre in C++ ciò è impossibile a meno di fare ricorso a librerie esterne. Comunque è possibile chiedere se due oggetti sono o meno dello stesso tipo (inclusi i tipi predefiniti) e se un oggetto è istanza di una data classe (o superclasse ).

L'uso della riflessione fa parte di una più ampia distinzione tra caratteristiche dinamiche ( run-time ) e statiche ( compile-time ) dei linguaggi. Sebbene sia Objective C che C++ implementino un misto di entrambe le caratteristiche, Objective C è decisamente più orientato verso le decisioni dinamiche, mentre C++ verso quelle effettuate al momento della compilazione.

Note

  1. ^ ( EN ) documento Apple , su lists.apple.com (archiviato dall' url originale il 18 giugno 2009) .
  2. ^ ( EN ) documento Apple , su lists.apple.com (archiviato dall' url originale il 24 novembre 2010) .
  3. ^ ( EN ) documento Apple , su developer.apple.com .
  4. ^ ( EN ) documento Apple , su apple.com . URL consultato il 3 maggio 2019 (archiviato dall' url originale il 15 dicembre 2008) .
  5. ^ ( EN ) Apple, Inc., Mac OS X Leopard – Xcode 3.0 , su apple.com , 22 agosto 2006. URL consultato il 22 agosto 2006 (archiviato dall' url originale il 24 ottobre 2007) .

Bibliografia

  • Object Oriented Programming: An Evolutionary Approach , Brad J. Cox - Addison Wesley (1991)

Collegamenti esterni

Controllo di autorità LCCN ( EN ) sh2008009199 · GND ( DE ) 4335874-3 · BNF ( FR ) cb14537421z (data)
Informatica Portale Informatica : accedi alle voci di Wikipedia che trattano di informatica