Cel C
| Cel C | ||
|---|---|---|
| ? | ||
| Informacje ogólne | ||
| Wspólne rozszerzenia | h, m, mm i C | |
| Paradygmat | zorientowany obiektowo | |
| Pojawił się w | 1980 | |
| Zaprojektowany przez | Brad Cox | |
| typ systemu | mocny, statyczny | |
| wdrożenia | liczny | |
| wpływem | C , mała rozmowa | |
| wpłynął | Cel-C++ , Java | |
Objective-C to zorientowany obiektowo język programowania stworzony jako nadzbiór języka C w celu zaimplementowania modelu obiektowego podobnego do Smalltalka . Został pierwotnie stworzony przez Brada Coxa i StepStone Corporation w 1980 roku . W 1988 roku został przyjęty jako język programowania NEXTSTEP , aw 1992 został wydany na licencji GPL dla kompilatora GCC . Obecnie jest używany jako główny język programowania dla Mac OS X , iOS i GNUstep , oprócz Szybki .
Historia
Na początku lat 80. oprogramowanie zostało opracowane przy użyciu programowania strukturalnego. Programowanie strukturalne powstało, aby pomóc w rozbiciu programów na małe części, ułatwiając programowanie, gdy aplikacja stała się bardzo duża. Jednak w miarę narastania problemów z czasem programowanie strukturalne stało się złożone, ponieważ niektórzy programiści robili bałagan, aby powtarzać instrukcje, co prowadziło do kodu spaghetti i utrudniało ponowne użycie kodu.
Wielu widziało, że programowanie obiektowe byłoby rozwiązaniem problemu. W rzeczywistości Smalltalk rozwiązał już wiele z tych problemów: niektóre z najbardziej złożonych systemów na świecie były zasilane przez Smalltalk. Ale Smalltalk używał maszyny wirtualnej, która wymagała na ten czas dużo pamięci i była zbyt wolna.
Objective-C został stworzony głównie przez Brada Coxa i Toma Love na początku lat 80. w ich firmie Stepstone. Oba zostały wprowadzone do Smalltalk w 1981 roku w Centrum Technologii Programowania ITT. Cox zainteresował się kwestiami ponownego wykorzystania w rozwoju oprogramowania. Zdał sobie sprawę, że język taki jak Smalltalk byłby niezbędny w tworzeniu potężnych środowisk programistycznych dla programistów w ITI Corporation. Cox zaczął modyfikować kompilator C, aby dodać niektóre możliwości Smalltalka. Wkrótce miał rozszerzenie, aby dodać programowanie obiektowe do C, które nazwał "OOPC" ( Programowanie zorientowane obiektowo w C ). Tymczasem Love został zatrudniony przez Shlumberger Research w 1982 roku i miał okazję nabyć pierwszy egzemplarz Smalltalk-80, co wpłynęło na jego styl jako programisty.
Aby zademonstrować, że dokonano prawdziwego postępu, Cox wykazał, że stworzenie naprawdę wymiennych komponentów oprogramowania wymaga jedynie niewielkich zmian w istniejących narzędziach. W szczególności musieli obsługiwać obiekty w elastyczny sposób, dostarczać zestaw użytecznych bibliotek i umożliwiać pakowanie kodu (i wszelkich zasobów wymaganych przez kod) w formacie międzyplatformowym.
Następnie Cox and Love założył nową firmę Productivity Products International (PPI), aby promować swój produkt, który był kompilatorem Objective-C z zestawem potężnych bibliotek.
W 1986 roku Cox opublikował główny opis Celu-C w jego oryginalnej formie w książce Object-Oriented Programming, An Evolutionary Approach . Chociaż ostrożnie zwrócił uwagę, że istnieje wiele problemów związanych z ponownym użyciem, które nie są zależne od języka, Objective-C był często szczegółowo porównywany z innymi językami.
Popularyzacja przez NeXT
W 1988 NeXT udzielił licencji na Objective-C od StepStone (nowa nazwa dla PPI, właściciela marki Objective-C) i rozszerzył kompilator GCC o obsługę Objective-C, jednocześnie rozwijając biblioteki AppKit i Foundation.Kit, na którym użytkownik NeXTstep zostały oparte . Chociaż stacje robocze NeXT nie wywarły dużego wpływu na rynek, narzędzia te były szeroko chwalone w branży. To skłoniło NeXT do porzucenia produkcji sprzętu i skupienia się na narzędziach programowych, sprzedając NeXTstep (i OpenStep) jako platformę do niestandardowego programowania.
Pracami nad rozszerzeniem GCC kierował Steve Naroff, który dołączył do NeXT z StepStone. Zmiany kompilatora zostały udostępnione na warunkach licencji GPL , ale nie w bibliotekach wykonawczych, przez co wkład open source nie nadaje się do użytku dla ogółu społeczeństwa. To skłoniło inne firmy do rozwijania tych bibliotek na licencjach open source. Później Steve Naroff był także głównym wkładem w prace Apple nad interfejsem Objective-C Clang .
Projekt GNU rozpoczął prace nad implementacją wolnego oprogramowania Cocoa, zwaną GNUstep i opartą na standardzie OpenStep. [ 1 ] Dennis Glatting napisał pierwszy system uruchomieniowy GNU Objective-C w 1992 roku. System uruchomieniowy GNU Objective-C, który jest używany od 1993 roku, jest jednym z tych opracowanych przez Krestena Kraba Thorupa, gdy był studentem college'u w Danii . Thorup pracował również w NeXT od 1993 do 1997 roku.
Rozwój Apple i Swift
Po przejęciu NeXT w 1996 roku Apple używał OpenStep w swoim nowym systemie operacyjnym, Mac OS X. Obejmowało to narzędzie programistyczne Objective-C i NeXT oparte na Objective-C, Project Builder (później rozszerzone i teraz znane jako Xcode ), a także narzędzie do projektowania interfejsów, Interface Builder. Większość obecnych interfejsów API Cocoa firmy Apple jest oparta na obiektach interfejsu OneStep i jest to najczęściej używane środowisko programistyczne Objective-C do aktywnego programowania.
Na WWDC 2014 firma Apple ogłosiła plany zastąpienia Objective-C w rozwoju Cocoa nowym językiem Swift , który nazywa się „Objective-C bez C”.
Składnia
Objective-C składa się z bardzo cienkiej warstwy na wierzchu C i jest również ścisłym nadzbiorem C . Oznacza to, że można skompilować dowolny program napisany w języku C za pomocą kompilatora Objective-C, a także można swobodnie dołączyć kod C do klasy Objective-C.
Oznacza to, że do napisania klasycznego programu „Hello World” uruchamianego na konsoli można użyć następującego kodu:
#import <stdio.h>
int main ( int argc , const char * argv [] ) {
printf ( "Witaj świecie \n " );
zwróć 0 ;
}
Powyższy kod różni się od zwykłego kodu C pierwszą instrukcją #import, która różni się od #include klasycznego C, ale funkcja printf("") jest czystym C. Własna funkcja Objective-C do drukowania ciągu znaków w konsoli to NSLog(@""); używając go, poprzedni kod wyglądałby następująco:
int main ( int argc , const char * argv [] ) {
NSLog ( @"Witaj świecie \n " );
zwróć 0 ;
}
Składnia obiektu Objective-C wywodzi się z Smalltalk . Cała składnia operacji niezorientowanych obiektowo (w tym zmienne pierwotne, przetwarzanie wstępne, wyrażenia, deklaracje funkcji i wywołania funkcji) jest identyczna z C, podczas gdy składnia funkcji zorientowanych obiektowo jest implementacją podobną do obsługi komunikatów Smalltalk.
Wiadomości
Obiektowy model programowania Objective-C opiera się na wysyłaniu komunikatów do instancji obiektów. Różni się to od modelu programowania w stylu Simula używanego przez C++ i to rozróżnienie jest semantycznie ważne. W Objective-C nie wywołuje się metody ; wysyła się komunikat , a różnica między tymi dwoma pojęciami polega na tym, jak wykonywany jest kod, do którego odnosi się komunikat lub nazwa metody. W języku w stylu Simula nazwa metody jest w większości przypadków powiązana z sekcją kodu w klasie docelowej przez kompilator, ale w Smalltalk i Objective-C komunikat jest nadal tylko nazwą i jest rozwiązywany w czasie wykonywania: obiekt odbierający ma za zadanie zinterpretować samą wiadomość. Jedną z konsekwencji tego jest to, że komunikat systemowy, który przekazuje, nie jest sprawdzany pod względem typu: obiekt, do którego jest adresowana wiadomość (znany jako odbiorca ), nie ma z natury gwarancji, że odpowie na wiadomość, a jeśli nie, po prostu ignoruje go i zwraca wskaźnik null.
Wysłanie komunikatu o metodzie do obiektu wskazywanego przez wskaźnik obj wymagałoby następującego kodu C++:
obj -> metoda ( parametr );
podczas gdy w Objective-C byłoby to napisane w następujący sposób:
[ metoda obj : parametr ];
Oba style programowania mają swoje mocne i słabe strony. OOP w stylu symulacji umożliwia wielokrotne dziedziczenie i szybkie wykonywanie przy użyciu powiązania w czasie kompilacji, gdy jest to możliwe, ale domyślnie nie obsługuje wiązania dynamicznego. Wymusza to, aby wszystkie metody miały odpowiednią implementację, chyba że są wirtualne (implementacja metody jest nadal wymagana do wykonania wywołania). OOP w stylu Smalltalk pozwala, aby komunikaty nie wymagały implementacji — na przykład cała kolekcja obiektów może wysyłać komunikat bez obaw o błędy w czasie wykonywania. Wysyłanie wiadomości również nie wymaga definiowania obiektu w czasie kompilacji. (Zobacz sekcję dynamicznego pisania poniżej ), aby uzyskać więcej zalet dynamicznego wiązania.
Należy jednak zauważyć, że ze względu na narzut związany z interpretacją komunikatów, komunikat w Objective-C trwa w najlepszym razie trzy razy dłużej niż wywołanie metody wirtualnej w C++. [ 2 ]
Interfejsy i implementacje
Objective-C wymaga, aby interfejs i implementacja klasy znajdowały się w oddzielnych blokach kodu. Zgodnie z konwencją interfejs jest umieszczany w pliku nagłówkowym, a implementacja w pliku kodu; pliki nagłówkowe, zwykle z rozszerzeniem .h, są podobne do plików nagłówkowych C; pliki implementacyjne (metody), które zazwyczaj mają rozszerzenie .m, mogą być bardzo podobne do plików kodu C.
Interfejs
Interfejs klasy jest zwykle zdefiniowany w pliku nagłówkowym. Powszechną konwencją jest nazywanie pliku nagłówkowego taką samą nazwą jak klasa. Interfejs dla klasy Class należy zatem znaleźć w pliku Class.h .
Deklaracja interfejsu formularza:
@interface nazwa klasy : nazwa superklasy
{
// zmienne instancji
}
+ klasaMetoda1 ;
+( typ_zwrotu ) classMethod2 ;
+( return_type ) classMethod3: ( param1_type ) parametr_varName ;
-( typ_zwrotu ) metoda_wystąpienia1 : ( typ_parametru1 ) nazwa_zmiennej_parametru1 : ( typ_zmiennej_parametru2 ) nazwa_zmiennej_parametru2 ;
-( return_type ) instanceMethod2WithParameter: ( param1_type ) param1_varName iOtherParameter : ( param2_type ) param2_varName ;
@koniec
Znaki plus oznaczają metody klas, znaki minus oznaczają metody instancji. Metody klas nie mają dostępu do zmiennych instancji.
Jeśli pochodzisz z C++, powyższy kod jest odpowiednikiem czegoś takiego:
klasa nazwa klasy : nazwa superklasy {
publiczny :
// zmienne instancji
// Funkcje klas (statyczne) static void * classMethod1 ();
statyczny return_type classMethod2 ();
statyczny return_type classMethod3 ( param1_type parametr_varName );
// Funkcje instancji (członków)
return_type instanceMethod1 ( param1_type param1_varName , param2_type param2_varName );
return_type instanceMethod2WithParameter ( param1_type param1_varName , param2_type param2_varName = default );
};
Należy zauważyć, że instanceMethod2WithParameterdemonstruje możliwość nazewnictwa parametrów Objective-C, dla których nie ma bezpośredniego odpowiednika w C/C++.
Typy zwracane mogą być dowolnym standardowym typem C, wskaźnikiem do ogólnego obiektu Objective-C lub wskaźnikiem do określonego typu, takiego jak NSArray *, NSImage * lub NSString *. Domyślnym typem zwracanym jest typ idogólny celu-C.
Argumenty metody zaczynają się od dwukropka, po którym następuje oczekiwany typ argumentu w nawiasach, po którym następuje nazwa argumentu. W niektórych przypadkach (np. podczas pisania systemowych API) warto dodać opisowy tekst przed każdym parametrem.
-( void ) setRangeStart: ( int ) start End: ( int ) end ;
-( void ) importDocumentWithName: ( NSString * ) name withSpecifiedPreferences: ( Preferences * ) prefs beforePage: ( int ) insertPage ;
Wdrożenie
Interfejs deklaruje tylko interfejs klasy, a nie same metody; rzeczywisty kod jest napisany w implementacji. Pliki (metody) implementacyjne mają zwykle rozszerzenie .m .
@nazwa klasy implementacji
+ klasaMetoda {
// wdrożenie
}
-instancjaMetoda { _
// wdrożenie
}
@koniec
Metody są pisane z ich deklaracjami interfejsów. Porównanie Celu C i C:
-( int ) metoda: ( int ) ja {
return [ własny pierwiastek_kwadratowy : i ];
}
funkcja int ( int ja ) {
zwróć pierwiastek_kwadratowy ( i );
}
Składnia obsługuje pseudonazywanie argumentów.
-( int ) changeColorToRed: ( float ) czerwony zielony: ( float ) zielony niebieski: ( float ) niebieski
[ myColor changeColorToRed : 5.0 zielony : 2.0 niebieski : 6.0 ];
Wewnętrzna reprezentacja tej metody różni się w zależności od różnych implementacji celu C. Jeśli myColor należy wewnętrznie do klasy Color , instancja metody -changeColorToRed:green:blue: może zostać oznaczona jako _i_Color_changeColorToRed_green_blue . Litera i odnosi się do instancji metody, której towarzyszą nazwy klas i metod, a dwukropek jest zastępowany przez podkreślenia. Ponieważ kolejność parametrów jest częścią nazwy metody, nie można jej zmienić w celu dopasowania do stylu kodowania.
Jednak nazwy funkcji wewnętrznych rzadko są używane bezpośrednio, a komunikaty są zwykle konwertowane na wywołania funkcji zdefiniowane w bibliotece wykonawczej Objective-C – metoda, która ma zostać wywołana, niekoniecznie jest znana w czasie wiązania: klasa odbiorcy (obiekt, który wysłał komunikat) nie musi o tym wiedzieć do czasu uruchomienia.
Instancja
Gdy klasa zostanie napisana w Objective-C, można ją utworzyć. Odbywa się to poprzez alokację pamięci dla nowego obiektu, a następnie inicjowanie go. Obiekt nie jest w pełni funkcjonalny, dopóki oba kroki nie zostaną zakończone. Te kroki są zwykle wykonywane za pomocą jednej linii kodu:
MyObject * o = [[ MyObject alloc ] init ];
Wywołanie alloc przydziela wystarczającą ilość pamięci do przechowywania wszystkich zmiennych instancji dla obiektu, a wywołanie init można nadpisać, aby ustawić zmienne instancji na określone wartości w czasie tworzenia. Metoda init jest często zapisywana w następujący sposób:
-( id ) początek {
self = [ super init ];
jeśli ( własna ) {
ivar1 = ''' wartość1 ''' ;
ivar2 = wartość2 ;
.
.
.
}
zwróć siebie ;
}
Protokoły
Objective-C został rozszerzony w NeXT , aby wprowadzić koncepcję wielokrotnego dziedziczenia ze specyfikacji, ale nie z implementacji, poprzez wprowadzenie protokołów . Jest to realny model, jako wielodziedziczna abstrakcyjna klasa bazowa w C++ lub jako "interfejs" (jak w Javie lub C# ). Objective-C korzysta z protokołów ad hoc, zwanych protokołami nieformalnymi , a kompilator musi przestrzegać tak zwanych protokołów formalnych .
Wpisywanie dynamiczne
Objective-C, podobnie jak Smalltalk, może używać dynamicznego typowania : obiekt może otrzymać wiadomość, która nie jest określona w jego interfejsie. Pozwala to na zwiększenie elastyczności, ponieważ umożliwia obiektowi „złapanie” wiadomości i wysłanie jej do innego obiektu, który może odpowiednio odpowiedzieć na tę wiadomość lub w podobny sposób przekazać wiadomość do innego obiektu. To zachowanie jest znane jako przekazywanie lub delegowanie wiadomości (patrz poniżej). Alternatywnie można użyć procedury obsługi błędów w przypadku, gdy wiadomość nie może zostać przekazana. Jeśli obiekt nie przekazuje wiadomości, nie odpowiada na nią ani nie obsłuży błędu, system zgłosi wyjątek w czasie wykonywania. Jeśli komunikaty są wysyłane do nil (wskaźnik obiektu o wartości null), zostaną one po cichu zignorowane lub wywołają ogólny wyjątek, w zależności od opcji kompilatora.
Informacje wpisane statycznie można opcjonalnie dodać do zmiennych. Informacje te są następnie sprawdzane w czasie kompilacji. W kolejnych czterech stwierdzeniach podane są coraz bardziej szczegółowe rodzaje informacji. Te deklaracje są równoważne w czasie wykonywania, ale dodatkowe informacje umożliwiają kompilatorowi ostrzeżenie programisty, jeśli przekazany argument nie jest zgodny z określonym typem.
- ( nieważne ) setMyValue: ( id ) foo ;
W powyższej deklaracji foo może być dowolnej klasy.
- ( nieważne ) setMyValue: ( id < NSCopying > ) foo ;
W powyższej deklaracji foo może być instancją dowolnej klasy, która spełnia wymagania protokołu NSCopying .
- ( void ) setMyValue: ( NSNumber * ) foo ;
W powyższej deklaracji foo musi być instancją klasy NSNumber .
- ( void ) setMyValue: ( NSNumber < NSCopying > * ) foo ;
W powyższej deklaracji foo musi być instancją klasy NSNumber i musi być zgodne z protokołem NSCopying .
Przekazywanie
Objective-C pozwala na wysłanie wiadomości do obiektu, który może nie odpowiadać. Zamiast odpowiadać lub po prostu ignorować wiadomość, obiekt może przekazać wiadomość do innego obiektu, który może na nią odpowiedzieć. Przekazywanie może służyć do uproszczenia implementacji pewnych wzorców projektowych , takich jak obserwator lub proxy .
Środowisko wykonawcze Objective-C określa kilka metod w Object:
- metody spedycyjne:
- ( retval_t ) forward: ( SEL ) sel args: ( arglist_t ) args ; // z GCC - ( id ) forward : ( SEL ) sel args : ( marg_list ) args ; // z systemami NeXT/Apple
- metody działania:
- ( retval_t ) performv: ( SEL ) sel args: ( arglist_t ) args ; // z GCC - ( id ) performV: ( SEL ) sel args ( marg_list ) args ; // z systemami NeXT/Apple
Obiekt, który chce zaimplementować przekazywanie, musi tylko zastąpić metodę przekazywania nową metodą, która definiuje zachowanie do przodu. Metoda akcji performv::nie musi być przesłonięta, ponieważ ta metoda wykonuje jedynie akcję opartą na selektorze i argumentach. Type SELto typ wiadomości w Objective-C.
Uwaga: w openStep, Cocoa i GNUstep, powszechnie używanych obszarach roboczych Objective-C, nie musisz używać Object. metoda - (void)forwardInvocation:(NSInvocation *)anInvocationklasy NSObjectsłuży do wykonania przekazywania.
Przykład
Oto przykład programu, który demonstruje podstawy przekazywania.
- Spedytor.h
# importuj <objc/Object.h>
@interface Forwarder : Obiekt {
odbiorca identyfikatora ; // Obiekt, do którego chcemy przekazać wiadomość. }
// Metody akcesorów
- ( id ) odbiorca ;
- ( id ) setRecipient: ( id ) _odbiorca ;
@koniec
- Spedytor.m
# import "Forwarder.h"
@implementation Forwarder
- ( retval_t ) forward: ( SEL ) sel args: ( arglist_t ) args {
/*
* Sprawdź, czy odbiorca odpowiada na wiadomość.
* Może to być pożądane lub nie, na przykład, jeśli odbiorca
* nie odpowie z kolei na wiadomość, może ją ponownie wysłać.
*/
if ([ odbiorca odpowiadaToSelector : sel ]) {
return [ wykonanie odbiorcy : argumenty sel : argumenty ] ;
} jeszcze {
return [ błąd własny : "Odbiornik nie odpowiada" ];
}
}
- ( id ) setRecipient: ( id ) _odbiorca {
[ automatyczne zwolnienie odbiorcy ];
kontener = [ _zachowanie odbiorcy ] ;
zwróć siebie ;
}
- ( id ) odbiorca {
odbiorca zwrotu ;
}
@koniec
- Odbiorca.h
# import <objc/Object.h>
// Prosty obiekt odbierający. @interface Odbiorca : Obiekt
- ( id ) cześć ;
@koniec
- Odbiorca.m
# import "Recipient.h"
@implementation Odbiorca
- ( id ) witam {
printf ( "Odbiorca mówi cześć! \n " );
zwróć siebie ;
}
@koniec
- main.m
# import "Forwarder.h"
# import "Recipient.h"
int main ( void ) {
Spedytor * forwarder = [ Spedytor nowy ];
Odbiorca * odbiorca = [ Odbiorca nowy ];
[ zestaw spedytoraOdbiorca : odbiorca ]; // Wybierz odbiorcę. /* * Zobacz, czy nadawca nie odpowiada na powitanie! Zostanie przekazany. * Wszystkie nierozpoznane metody zostaną przekazane do odbiorcy * (jeśli odbiorca zareaguje na nie, jak podano w Forwarder) */
[ spedytor cześć ];
[ wydanie odbiorcy ];
[ zwolnienie spedytora ];
zwróć 0 ;
}
Notatki
Po skompilowaniu za pomocą gcc kompilator zgłasza:
$ gcc -x objective-c -Wno-import Forwarder.m Recipient.m main.m -lobjc
main.m: W funkcji `main':
main.m:12: ostrzeżenie: `Forwarder' nie odpowiada na `hello'
$
Kompilator zgłasza, jak skomentowano wcześniej, że nie odpowiada na Forwarderwiadomości hello . W takiej sytuacji można bezpiecznie zignorować ostrzeżenie, ponieważ zaimplementowano przekazywanie. Uruchomienie programu daje następujące dane wyjściowe:
& ./a.out
Odbiornik mówi cześć!
Warianty językowe
Cel-C++
Objective-C++ to wariant języka obsługiwany przez interfejs GNU Compiler Collection i Clang , który może kompilować pliki kodu źródłowego, które używają kombinacji składni C++ i Objective-C. Objective-C++ dodaje do C++ rozszerzenia, które Objective-C dodaje do C. Ponieważ nie robi się nic w celu ujednolicenia semantyki za funkcjami różnych języków, istnieją pewne ograniczenia:
- Klasa C++ nie może pochodzić z klasy celu C i na odwrót.
- Przestrzenie nazw C++ nie mogą być deklarowane w deklaracji celu-C.
- Deklaracje celu C muszą pojawiać się globalnie, a nie w ramach deklaracji C++.
- Klasy Objective-C nie mogą mieć zmiennych instancji klas C++, które nie mają domyślnego konstruktora lub mają jedną lub więcej metod wirtualnych, ale wskaźniki do obiektów C++ mogą być używane jako zmienne instancje bez ograniczeń (są one przypisane w metodzie -init).
- Semantyki "według wartości" C++ nie można zastosować do obiektów Objective-C, które są dostępne tylko za pomocą wskaźników.
- Deklaracja Objective-C nie może znajdować się w szablonie deklaracji C++ i na odwrót. Jednak typy Objective-C (takie jak Classname * ) mogą być używane jako parametry szablonu C++.
- Obsługa wyjątków Objective-C i C++ jest inna; każdy język może obsługiwać tylko własne wyjątki. Jest to łagodzone w najnowszych wersjach przez całkowite zastąpienie wyjątków Objective-C wyjątkami C++ (jak robi Apple) lub częściowo przez połączenie biblioteki Objective-C++ (GNUstep libobjc2).
- Należy zachować ostrożność, ponieważ wywołania destruktorów wyjątków celu-C i C++ w czasie wykonywania nie są zgodne (na przykład destruktor C++ nie zostanie wywołany, gdy wyjątek celu-C wyjdzie poza zakres obiektu C++). Nowsze wersje 64-bitowe rozwiązują ten problem, wprowadzając współdziałanie z wyjątkami C++ w tym zakresie. [ 3 ]
- Bloki celu C i lambdy C++11 to różne jednostki, jednak blok jest generowany w sposób przezroczysty w systemie Mac OS X, gdy lambda jest przekazywana w miejscu, w którym oczekiwany jest blok. [ 4 ]
Cel-C 2.0
Na konferencji Worldwide Developers Conference 2006 firma Apple ogłosiła wydanie „Objective-C 2.0”, rewizji języka Objective-C, która obejmuje „nowoczesne wyrzucanie elementów bezużytecznych, ulepszenia składni, [ 5 ] ulepszenia wykonywania [ 6 ] i 64-bitowy Pomoc". Mac OS X v10.5 , wydany w październiku 2007, zawierał kompilator Objective-C 2.0. GCC 4.6 obsługuje wiele nowych aplikacji Objective-C, takich jak zadeklarowane i zsyntetyzowane właściwości, składnia z kropkami, szybkie wyliczanie, opcjonalne metody protokołów, atrybuty metody/protokołu/klasy, rozszerzenia klas oraz nowy interfejs API GNUnn Objective-C . [ 7 ]
Zbieranie śmieci
Cel 2.0 miał opcjonalny konserwatywny odśmiecacz . Podczas pracy w trybie kompatybilności wstecznej zmieniał operacje zliczania odwołań , takie jak "wstrzymaj" i "zwolnij" na NOP ( No Operations , instrukcja asemblera wskazująca, że procesor nie musi nic robić). Wszystkie obiekty zostały przesłane do garbage collectora, gdy odśmiecanie było włączone. Wskaźniki C mogą być kwalifikowane za pomocą „__strong”, aby spowodować, że kompilator przechwyci zapisy, a tym samym weźmie udział w usuwaniu elementów bezużytecznych. [ 8 ] Zapewniono również słaby podsystem zerowania, w którym wskaźniki oznaczone jako „__słabe” były zerowane podczas gromadzenia obiektu (lub prościej pamięci modułu odśmiecania pamięci). Moduł odśmiecania pamięci nie istniał w implementacji Objective-C 2.0 systemu iOS. [ 9 ] Odśmiecanie w Objective-C działa w wątku o niskim priorytecie i może zatrzymywać zdarzenia użytkownika, aby zachować responsywność środowiska użytkownika. [ 10 ]
Zbieranie śmieci nigdy nie było dostępne w systemie iOS z powodu problemów z wydajnością. Został przestarzały w wersji 10.8 OS X na rzecz automatycznego zliczania referencji (ARC) i ma zostać usunięty w przyszłej wersji OS X. [ 11 ] Objective-C w iOS 7 wykonywany na ARM64 używa 19 bitów 64 -bitowe słowo do przechowywania licznika odwołań, jako forma wskaźnika z etykietą. [ 12 ] [ 13 ]
Właściwości
W celu 2.0 wprowadzono nową składnię do deklarowania zmiennych instancji jako właściwości z opcjonalnymi atrybutami do konfigurowania generowania metod akcesorów. Właściwości są w pewnym sensie zmiennymi instancji publicznych; oznacza to, że zadeklarowanie zmiennej instancji jako właściwości daje klasom zewnętrznym dostęp (prawdopodobnie ograniczony, na przykład tylko do odczytu ) do tej właściwości. Właściwość może być zadeklarowana jako „tylko do odczytu” i może być wyposażona w semantykę przechowywania, taką jak „assign” , „copy” lub „retain ” . Domyślnie właściwości są uważane za niepodzielne, co powoduje blokadę, która uniemożliwia wielu wątkom dostęp do nich w tym samym czasie. Właściwość można zadeklarować jako „nieatomową” , co usuwa to ubezpieczenie.
@interface Osoba : NSObject {
@publiczny
NSString * nazwa ;
@prywatny
wiek ; _
}
@property ( kopia ) NSString * nazwa ;
@property ( tylko do odczytu ) int wiek ;
-( id ) startWithAge: ( int ) wiek ;
@koniec
Właściwości są implementowane za pomocą słowa kluczowego @synthesize, które generuje metody pobierające (i ustawiające, jeśli nie tylko do odczytu) zgodnie z deklaracją właściwości. Alternatywnie metody pobierające i ustawiające muszą być zaimplementowane jawnie lub można użyć słowa kluczowego @dynamic, aby wskazać, że metody akcesora muszą być dostarczone w inny sposób. Podczas kompilacji przy użyciu Clang 3.1 lub nowszego wszystkie właściwości, które nie są jawnie zadeklarowane za pomocą @dynamic, nie są sprawdzane readonlylub nie mają pełnych metod zaimplementowanych przez użytkownika getteri setter, zostaną automatycznie @synthesizezadeklarowane niejawnie.
@osoba wdrożeniowa
@syntezowa nazwa ;
-( id ) startWithAge: ( int ) startAge {
self = [ super inicjał ];
jeśli ( własna ) {
wiek = wiek początkowy ; // UWAGA: bezpośrednie przypisanie zmiennej instancji, a nie właściwość ustawiająca }
zwróć siebie ;
}
-( int ) wiek {
wiek powrotu ;
}
@koniec
Dostęp do właściwości można uzyskać przy użyciu tradycyjnej składni przekazywania komunikatów, notacji z kropkami lub, w kodowaniu klucz-wartość, za pomocą valueForKey:/ metod setValue:forKey.
Osoba * aPerson = [[ Przypisanie osób ] startWithAge : 53 ];
aOsoba . nazwa = @"Steve" ; // UWAGA: notacja z kropkami używa syntetyzowanego setera, // równoważnego z [NazwaZestawu Osoby: @"Steve"]; NSLog ( @"Dostęp za pomocą wiadomości (%@), notacja z kropką (%@), nazwa właściwości ( % @ ) i bezpośredni dostęp do zmiennej instancji ( % @) " , [ aPerson name ] , aPerson . name , [ aPerson valueForKey : @"imię" ], aOsoba -> imię );
Aby użyć notacji z kropką do wywołania właściwości akcesora w metodzie instancji, należy użyć słowa kluczowego "self":
-( void ) wprowadźMeWithProperties : ( BOOL ) useGetter {
NSLog ( @"Cześć, nazywam się %@." , ( useGetter ? self . name : name ));
// UWAGA: pobierający kontra dostęp ivar
}
Właściwości klasy lub protokołu można introspekcji dynamicznie.
int ja ;
int licznikwlasciwosci = 0 ;
objc_property_t * propertyList = copyPropertyList_class ([ aPerson class ], & propertyCount );
for ( i = 0 ; i < licznik właściwości ; i ++ ) {
objc_property_t * thisProperty = propertyList + i ;
const char * propertyName = property_getName ( * thisProperty );
NSLog ( @"Osoba ma właściwość: '%s'" , propertyName );
}
Niekruche zmienne instancji
Objective-C 2.0 zapewnia niewrażliwe zmienne instancji obsługiwane przez środowisko wykonawcze (na przykład tworzenie kodu dla 64-bitowego systemu Mac OS X, a także kodu dla wszystkich systemów iOS). W nowoczesnym środowisku wykonawczym dodawana jest dodatkowa warstwa odchyleń w celu tworzenia instancji zmiennych dostępu, umożliwiając dynamicznemu linkerowi dostosowanie płaszczyzny tworzenia instancji w czasie wykonywania. Ta właściwość umożliwia dwa duże ulepszenia kodu celu-C:
- Eliminuje problem kruchych interfejsów binarnych - superklasy mogą zmieniać swój rozmiar bez wpływu na kompatybilność binarną.
- Umożliwia syntezowanie zmiennych instancji, które zapewniają wsteczną kompatybilność właściwości, w czasie wykonywania bez ich deklaracji w interfejsie klasy.
Szybkie wyliczenie
Zamiast używać obiektu NSEnumerator lub wskazywać iterację w kolekcji, Objective-C 2,0 oferuje składnię szybkiego wyliczania. W Objective-C 2.0 następujące pętle są funkcjonalnie równoważne, ale mają różne charakterystyki wydajności.
// Korzystanie z NSEnumeratora
NSEnumerator * enumerator = [ thePeople objectEnumerator ] ;
Osoba * p ;
while (( p = [ enumerator nextObject ]) != nil ) {
NSLog ( @"%@ ma %i lat." , [ p nazwa ], [ strona ] );
}
// Używając indeksów
for ( int i = 0 ; i < [ liczba osób ] ; i ++ ) {
Osoba * p = [ thePeople objectAtIndex : i ];
NSLog ( @"%@ ma %i lat." , [ p nazwa ], [ strona ] );
}
// Używanie szybkiego wyliczania
dla ( Osoba * p w Ludzie ) {
NSLog ( @"%@ ma %i lat." , [ p nazwa ], [ strona ] );
}
Szybkie wyliczanie generuje bardziej wydajny kod niż standardowe wyliczanie, ponieważ wywołania metod do wyliczania obiektów są zastępowane przez arytmetykę wskaźnika przy użyciu protokołu NSFastEnumeration.
Rozszerzenie klasy
Rozszerzenie klasy ma taką samą składnię jak deklaracja kategorii bez nazwy kategorii, a zadeklarowane w nim metody i właściwości są dodawane bezpośrednio do klasy main. Jest używany głównie jako alternatywa dla kategorii w celu dodawania metod do klasy bez deklarowania ich w publicznych nagłówkach, z tą zaletą, że w przypadku rozszerzeń klas kompilator sprawdza, czy wszystkie zadeklarowane prywatnie metody są faktycznie zaimplementowane. [ 7 ]
Bloki
Bloki to niestandardowe rozszerzenie do Objective-C (a także C i C++ ), które używa specjalnej składni do tworzenia zamknięć . Bloki są obsługiwane tylko w systemie Mac OS X 10.6 „Snow Leopard” lub nowszym oraz iOS 4 lub nowszym, a także GNUstep z libobjc2 1.7 i skompilowanym z Clang 3.1 lub nowszym. [ 14 ]
#włącz <stdio.h>
#zawiera <Block.h>
typedef int ( ^ IntBlock )();
IntBlock MakeCounter ( int start , int increment ) {
__block int i = początek ;
return Block_copy ( ^ {
int ret = i ;
i += przyrost ;
powrót ret ;
});
}
int główna ( nieważne ) {
IntBlock mójlicznik = MakeCounter ( 5 , 2 );
printf ( "Pierwsze wywołanie: %d \n " , mójlicznik ());
printf ( "Drugie wywołanie: %d \n " , mójlicznik ());
printf ( "Trzecie wywołanie: %d \n " , mójlicznik ());
/* ponieważ został skopiowany, musi również zostać wydany */
block_release ( mycounter );
zwróć 0 ;
}
/* Dane wyjściowe:
Pierwsze wywołanie: 5
Drugie wywołanie: 7
Trzecie wywołanie: 9
*/
Nowoczesny cel-C
Automatyczne Liczenie Referencji
Automatyczne zliczanie referencji ( ARC ) to funkcja czasu kompilacji, która eliminuje potrzebę ręcznego zapisywania zliczeń przez programistów za pomocą retaini release. [ 11 ] W przeciwieństwie do modułu odśmiecania pamięci , który działa w czasie wykonywania, ARC usuwa obciążenie oddzielnego procesu zarządzania przechowywaniem kont. ARC i ręczne zarządzanie pamięcią nie wykluczają się wzajemnie; programiści mogą nadal używać kodu innego niż ARC w projektach, w których włączono ARC, wyłączając ARC dla pojedynczego kodu źródłowego. Xcode może również próbować automatycznie uaktualnić projekt do ARC.
Literały
Środowiska wykonawcze NeXT i Apple Obj-C dawno temu zawierały skrót do tworzenia nowych ciągów za pomocą składni literalnej, @"una nueva cadena"a także porzucały stałe CoreFoundation kCFBooleanTruei wartości kCFBooleanFalsezmiennych binarnych NSNUmber. Używanie tego formatu uwalnia programistę od używania najdłuższych initWithStringlub podobnych metod podczas wykonywania pewnych operacji.
Korzystając z kompilatora Apple LLVM 4.0 lub nowszego, tablice, słowniki i liczby (klasy i NSAray) można również tworzyć przy użyciu składni dosłownej zamiast metod. [ 15 ] Składnia dosłowna używa odpowiednio symbolu połączonego z , lub do utworzenia klas wymienionych powyżej. [ 16 ]
NSDictionaryNSNumber@[]{}()
Przykład bez literałów:
NSArray * myVector = [ NSArray arrayWithObjects : obiekt1 , obiekt2 , obiekt3 , nil ];
NSDictionary * myDictionary1 = [ NSDictionary dictionaryWithObject : anObject forKey : @"klucz" ];
NSDictionary * myDictionary2 = [ NSDictionary dictionaryWithObjectsAndKeys : object1 , key1 , object2 , key2 , nil ];
NSNumber * myNumber = [ NSNnumer numberWithInt : myInt ];
NumerNs * sumaNumer = [ NnumerNumerZInt :( 2 + 3 ) ];
NSNumber * mojaBooleanNumber = [ NSNnumer numberWithBoolean : YES ];
Przykład z literałami:
NSArray * myVector = @[ obiekt1 , obiekt2 , obiekt3 ] ;
NSDictionary * myDictionary1 = { @"klucz" : anObject };
NSDictionary * myDictionary2 = { klucz1 : obiekt1 , klucz2 : obiekt2 };
NSNnumer * myNumber = @{ myInt } ;
NSNnumer * mojaNumerSum = @{ 2 + 3 } ;
NSNumber * mój numerBoolean = @TAK ;
Jednak w przeciwieństwie do literałów ciągów, które są kompilowane jako stałe w pliku wykonywalnym, te literały są kompilowane jako kod równoważny z wywołaniami metod wspomnianymi powyżej. W szczególności, w przypadku ręcznej obsługi zliczania odwołań do pamięci, obiekty te są samouwalniające się, co wymaga szczególnej ostrożności, gdy na przykład są używane ze statycznymi zmiennymi funkcyjnymi lub innymi typami zmiennych globalnych.
Indeksy
Korzystając z kompilatora Apple LLVM 4.0 lub nowszego, tablicami i słownikami ( klasy NSArrayi NSDictionary) można manipulować za pomocą indeksów dolnych. [ 15 ] Indeksy dolne mogą być używane do pobierania wartości z indeksów (wektorów) lub kluczy (słowników), a w przypadku obiektów mutowalnych można ich również używać do ustawiania obiektów na indeksy lub klucze. W kodzie indeksy dolne są reprezentowane za pomocą nawiasów kwadratowych [ ]. [ 16 ]
Przykłady bez indeksów:
id obiekt1 = [ aVector objectAtIndex : 0 ];
id obiekt2 = [ aDictionary objectForKey : @"klucz" ];
[ aVectorMutable replaceObjectAtIndex : 0 withObject : object3 ];
[ aMutableDictionary setObject : object4 forKey : @"klucz" ];
Przykłady z indeksami:
id obiekt1 = aWektor [ 0 ];
id obiekt2 = aSłownik [ @"klucz" ];
aMutableVector [ 0 ] = obiekt3 ;
aMutableDictionary [ @"klucz" ] = obiekt4 ;
„Nowoczesna” składnia celu-C (1997)
Po zakupie NeXT przez Apple podjęto kilka prób upodobnienia języka do innych istniejących języków. Jedną z takich prób było wprowadzenie „nowoczesnej składni” dla Objective-C (w przeciwieństwie do istniejącej „klasycznej” składni). Nie było żadnej zmiany w rzeczywistym zachowaniu, była to tylko alternatywna składnia. Wywołanie metody odbywało się w ten sposób:
obiekt = ( MojaKlasa . alloc ). początek ;
obiekt . pierwszyTag ( param1 , param2 );
A tak się złożyło, że zostało napisane w ten sposób:
obiekt = [[ MyClass alloc ] init ];
[ obiekt firstLabel : param1 secondLabel : param2 ];
Podobnie deklaracje wyszły z tego:
-( void ) firstLabel ( int param1 , int param2 );
być takim:
-( void ) pierwszyTag: ( int ) param1 secondTag: ( int ) param2 ;
Ta „nowoczesna” składnia nie jest obsługiwana w obecnych dialektach Objective-C.
Przenośny kompilator obiektów
Oprócz implementacji GCC / NeXT / Apple , które dodały różne rozszerzenia do oryginalnej implementacji Stepstone, istnieje również inna darmowa i otwarta implementacja Objective-C o nazwie Protable Object Compiler. [ 17 ] Zestaw rozszerzeń zaimplementowanych przez Portable Object Compiler różni się od implementacji GCC/NeXT/Apple; w szczególności zawiera bloki podobne do Smalltalk dla Objective-C, podczas gdy brakuje mu protokołów i kategorii, dwóch funkcji szeroko stosowanych w OpenStep i jego pochodnych. Podsumowując, POC reprezentuje starszy, pre-NeXT etap ewolucji języka, zgodnie z książką Brada Coxa z 1991 roku.
Zawiera również bibliotekę uruchomieniową o nazwie ObjectPak, która jest oparta na oryginalnej bibliotece ICPak101 Coxa (która sama wywodzi się z biblioteki klas Smalltalk-80) i jest radykalnie różna od OneStep FoundationKit.
Cel GEOS-C
System PC GEOS wykorzystywał język programowania znany jako GEOS Objective-C lub goc ; [ 18 ] Pomimo podobnej nazwy, oba języki są podobne pod względem ogólnej koncepcji i użycia słów kluczowych poprzedzonych znakiem @.
Klang
Zestaw kompilatorów Clang , część projektu LLVM , implementuje Objective-C, a także inne języki.
Zobacz także
Referencje
- ↑ „Wprowadzenie do GNUstep” (w języku angielskim) . Źródło 10 lipca 2014 .
- ^ „Porównania wydajności wspólnych operacji” . Zarchiwizowane z oryginału 1 lipca 2009 . Źródło 19 czerwca 2019 .
- ↑ "Korzystanie z C++ z Objective-C " . 19 listopada 2008. Zarchiwizowane od oryginału 31 grudnia 2008 . Źródło 10 lipca 2014 .
- ↑ „Dokumentacja Clang 3.5 — Współdziałanie z lambdami C++11 ” . Źródło 10 lipca 2014 .
- ↑ Dave Wasilewski (10 sierpnia 2006). „Cel-C 2.0: więcej wskazówek ” . Zarchiwizowane z oryginału w dniu 18 czerwca 2009 . Źródło 10 lipca 2014 .
- ^ Dietmar Planitzer (9 sierpnia 2006). „Re: Objective-C 2.0” (w języku angielskim) . Zarchiwizowane z oryginału w dniu 24 listopada 2010 . Źródło 10 lipca 2014 .
- ↑ a b „Wydanie serii GCC 4.6: zmiany, nowe funkcje i poprawki ” . Źródło 10 lipca 2014 .
- Jabłko . _ Interfejs API modułu zbierającego śmieci . Źródło 10 lipca 2014 .
- Jabłko . _ „Wprowadzenie do Garbage Collector ” . Źródło 10 lipca 2014 .
- ↑ Apple (6 listopada 2007). „Technologia Leopard dla programistów: Podsumowanie Objective-C 2.0 ” . Zarchiwizowane z oryginału w dniu 24 lipca 2010 . Źródło 10 lipca 2014 .
- ↑ a b Apple (17 lipca 2012). Uwagi dotyczące przejścia ARC . Źródło 10 lipca 2014 .
- ↑ Mike Ash (27 września 2013). „ARM64 i ty” (w języku angielskim) . Źródło 10 lipca 2014 .
- ↑ SealieSoftware.com (24 września 2013). „Objaśnienie celu C: ISA nie jest wskaźnikiem ” . Źródło 10 lipca 2014 .
- ↑ Apple (8 marca 2011). „Programowanie w blokach” (w języku angielskim) . Źródło 10 lipca 2014 .
- ↑ ab Apple . _ „Programowanie z Objective-C: wartości i kolekcje ” . Źródło 10 lipca 2014 .
- ↑ a b Clang . Literały celu C . Źródło 10 lipca 2014 .
- ↑ „Przenośny kompilator obiektów ” . Źródło 10 lipca 2014 .
- ^ "SDK GEOS " . Źródło 10 lipca 2014 .