Objective-C odvozuje syntaxi objektu od Smalltalku. Všechny syntaxe pro non-object-orientované operace (včetně primitivních proměnných, pre-zpracování, výrazy, funkce, deklarace a volání funkcí) jsou totožné C, zatímco syntaxe pro objektově orientované funkce je implementace Smalltalk-stylu zpráv.
MessagesEdit
Objective-C model objektově orientovaného programování je založen na předávání zpráv do instancí objektů. V Objective-C nelze volat metodu; jeden odešle zprávu., To je na rozdíl od simula stylu programovacího modelu používaného c++. Rozdíl mezi těmito dvěma pojmy spočívá v tom, jak je proveden kód odkazovaný metodou nebo názvem zprávy. V jazyce ve stylu Simula je název metody ve většině případů vázán kompilátorem na část kódu v cílové třídě. V Smalltalk a Objective-C je cíl zprávy vyřešen za běhu, přičemž samotný přijímající objekt interpretuje zprávu., Metoda je označena voliče nebo SEL — jedinečný identifikátor pro každou zprávu jménem, často jen NUL-ukončen řetězec představující jeho jméno — a rozhodl se C metoda ukazatel provádění: IMP. Důsledkem toho je, že systém předávání zpráv nemá kontrolu typu. Objekt, ke kterému se zpráva směřuje — přijímač — není zaručeno, že reagovat na zprávu, a pokud tomu tak není, vyvolává výjimku.,
Odeslání zprávy metodou k objektu, na který ukazuje ukazatel obj bude vyžadovat následující kód v C++:
obj->method(argument);
V Objective-C, je to napsáno takto:
;
„metoda“ call je přeložen kompilátorem do objc_msgSend(id self, SEL op …) rodina runtime funkcí. Různé implementace zvládnout moderní dodatky jako super. V rodinách GNU je tato funkce pojmenována objc_msg_sendv, ale byla zastaralá ve prospěch moderního vyhledávacího systému pod objc_msg_lookup.,
oba styly programování mají své silné a slabé stránky. Objektově orientované programování ve stylu Simula (C++) umožňuje vícenásobné dědičnosti a rychlejší provádění pomocí vazby compile-time, kdykoli je to možné, ale ve výchozím nastavení nepodporuje dynamickou vazbu. Také nutí všechny metody mít odpovídající implementaci, pokud nejsou abstraktní. Smalltalk-styl programování používaný v Objective-C umožňuje zprávy, které mají jít nerealizovaných, s metodou vyřešen k její implementaci za běhu., Například zpráva může být odeslána do sbírky objektů,na které se očekává, že budou reagovat pouze někteří, aniž by se obávali chyb za běhu. Předávání zpráv také nevyžaduje, aby byl objekt definován v době kompilace. Pro vyvolání metody v odvozeném objektu je stále nutná implementace. (Další výhody dynamické (pozdní) vazby naleznete v sekci dynamické psaní níže.)
Rozhraní a implementationsEdit
Objective-C vyžaduje, aby rozhraní a implementace třídy být samostatně deklarován bloky kódu., Podle konvence vývojáři umístí rozhraní do souboru záhlaví a implementaci do souboru kódu. Soubory záhlaví, obvykle přípony .h, jsou podobné hlavičkovým souborům C, zatímco soubory implementace (metoda), obvykle přípony .m, může být velmi podobný souborům kódu C.
InterfaceEdit
Toto je analogické s class prohlášení, jak je používán v jiných objektově orientovaných jazycích, jako je C++ nebo Python.
rozhraní třídy je obvykle definováno v souboru záhlaví. Společnou konvencí je pojmenovat soubor záhlaví za názvem třídy, např.,h by obsahovat rozhraní pro třídu míč.
rozhraní prohlášení má podobu:
výše uvedené, plus známky, označení třídy, metody, nebo metody, které lze volat na třídě sám (ne na instanci), a mínus označují instance metody, které lze volat pouze na konkrétní instanci třídy. Metody třídy také nemají přístup k proměnným instancí.,
výše uvedený kód je hrubě ekvivalentní k následující C++ rozhraní:
Všimněte si, že instanceMethod2With2Parameters:param2_callName: ukazuje prokládání voliče segmenty s argumentem výrazy, pro které neexistuje žádný přímý ekvivalent v C/C++.
Návrat typů může být jakýkoliv standardní typ C, ukazatel na obecný Cíl-objekt C, ukazatel na konkrétní typ objektu, jako NSArray *, NSImage *, nebo NSString *, nebo ukazatel do třídy, ke které metoda patří (instancetype). Výchozím typem návratu je obecné ID typu Objective-C.,
argumenty metody začínají názvem označujícím argument, který je součástí názvu metody, následovaný dvojtečkou následovanou očekávaným typem argumentu v závorkách a názvem argumentu. Štítek lze vynechat.
derivátem definice rozhraní je kategorie, která umožňuje přidat metody do stávajících tříd.
ImplementationEdit
rozhraní pouze prohlašuje, třídy, rozhraní a ne samotné metody: skutečný kód je napsán v souboru implementace., Provádění (metoda) soubory obvykle mají příponu .m
, který původně znamenal „zprávy“.
@implementation classname+ (return_type)classMethod { // implementation}- (return_type)instanceMethod { // implementation}@end
metody jsou psány pomocí deklarací rozhraní.Porovnání Objective-C a C:
- (int)method:(int)i { return ;}
int function(int i) { return square_root(i);}
syntaxe umožňuje pseudo-pojmenování argumentů.
interní reprezentace metody se liší mezi různými implementacemi cíle-C., Pokud má myColor barvu třídy, může být instance method-changecored: green: blue: interně označena _i_color_changecolored_green_blue. I je odkazovat na metodu instance, s názvy tříd a pak metod připojených a dvojtečky změněny na podtržítka. Jako pořadí parametrů je součástí metody jméno, nemůže být změněna, aby odpovídala kódování stylu nebo projevu jako s opravdovou pojmenované parametry.
interní názvy funkce se však zřídka používají přímo. Obecně jsou zprávy převedeny na volání funkcí definované v runtime knihovně Objective-C., V době propojení není nutně známo, která metoda bude volána, protože třída přijímače (objekt, který odesílá zprávu) nemusí být známa až do runtime.
InstantiationEdit
jakmile je napsána Třída Objective-C, může být instanciated. To se provádí nejprve přidělením nezasvěcené instance třídy (objektu) a poté inicializací. Objekt není plně funkční, dokud nejsou dokončeny oba kroky., Tyto kroky by mělo být provedeno s jeden řádek kódu tak, že nikdy není přiděleno objekt, který nebyl podroben inicializace (a protože to je moudré zachovat průběžný výsledek od -init
může vracet jiný objekt, než ten, na kterém je nazývá).,
Instance s výchozí, ne-parametr inicializátor:
MyObject *foo = init];
Instance s vlastní inicializátor:
MyObject *foo = initWithString:myString];
V případě, kde žádný vlastní inicializace je prováděna, „nová“ metoda může často být použity na místě alloc-init zprávy:
MyObject *foo = ;
Také některé třídy implementují metodu třídy inicializátory., Jako +new
, kombinují +alloc
-init
, ale na rozdíl od +new
, se vrátit autoreleased stupně. Některé metody třídy inicializátory vzít parametry:
MyObject *foo = ;MyObject *bar = ;
alloc zprávu přiděluje dostatek paměti držet všechny proměnné instance objektu, nastaví všechny proměnné instance na nulové hodnoty, a otočí paměti do instance třídy; v průběhu inicializace paměti instanci nadtřídy.,
zpráva init provádí nastavení instance při vytváření. Init metoda je často psán takto:
- (id)init { self = ; if (self) { // perform initialization of object here } return self;}
Ve výše uvedeném příkladu si všimněte, id
návratový typ. Tento typ znamená“ ukazatel na libovolný objekt “ v Objective-C (viz sekce dynamické psaní).
inicializátoru vzor se používá k zajištění, že objekt je správně inicializován její nadtřídy, než metoda init provede jeho inicializace., To provede následující akce:
- self = Odesílá nadřazené instance init zprávu a přiřadí výsledek do sebe (ukazatel na aktuální objekt).
- if (self)zkontroluje, zda je vrácený ukazatel objektu platný před provedením jakékoli inicializace.
- vrátit selfReturns hodnotu sebe volajícího.
non-platný objekt ukazatel má hodnotu nil; podmíněné příkazy, jako je „pokud“ léčit nil jako ukazatele null, takže inicializační kód se neprovede pokud je vrácena nulová., Pokud je chyba v inicializaci init metoda by měla provádět veškeré nezbytné vyčištění, včetně odesílání „vydání“ poselství vlastní, a vrátit nil uvést, že inicializace se nezdařila. Žádné kontroly pro tyto chyby musí být provedena pouze poté, co nazývá inicializace nadtřídy, aby zajistily, že zničení objektu bude provedeno správně.
pokud má třída více než jednu metodu inicializace, musí tento vzor následovat pouze jeden z nich („určený inicializátor“); jiní by měli zavolat určený inicializátor namísto inicializátoru superclass.,
ProtocolsEdit
v jiných programovacích jazycích se nazývají „rozhraní“.
Objective-C byl rozšířen na NeXT, aby představil koncept vícenásobné dědičnosti SPECIFIKACE, ale ne implementace, zavedením protokolů. Jedná se o vzor dosažitelný buď jako abstraktní vícenásobná zděděná základní třída v C++, nebo jako „rozhraní“ (jako v Javě a C#). Objective-C využívá protokolů ad hoc nazývaných neformální protokoly a protokoly vynucené kompilátorem nazývané formální protokoly.,
neformální protokol je seznam metod, které se třída může rozhodnout implementovat. Je uveden v dokumentaci, protože nemá v jazyce žádnou přítomnost. Neformální protokoly jsou implementovány jako kategorie (viz níže) na NSObject a často zahrnují volitelné metody, které, pokud jsou implementovány, mohou změnit chování třídy. Například třída textového pole může mít delegáta, který implementuje neformální protokol s volitelnou metodou pro automatické dokončení textu zadaného uživatelem., Textové pole zjistí, zda delegát implementuje tuto metodu (pomocí reflexe), a pokud ano, volá delegáta metoda na podporu auto-kompletní funkce.
formální protokol je podobný rozhraní v jazyce Java, C# A Ada 2005. Jedná se o seznam metod, které může každá třída prohlásit za implementované. Verze Objective-C 2.0 požadováno, že třída musí implementovat všechny metody v protokolu prohlašuje sám jako přijetí; kompilátor bude vydávat chybu, pokud třída neimplementuje všechny metody od její deklarované protokoly. Cíl-C 2.,0 přidána podpora pro označování určitých metod v protokolu volitelně, a kompilátor nebude prosazovat implementaci volitelných metod.
pro provedení tohoto protokolu musí být deklarována třída
, o které se říká, že je v souladu s tímto protokolem. To je detekovatelné za běhu. Formální protokoly nemohou poskytovat žádné implementace; jednoduše ujišťují volající, že třídy, které odpovídají protokolu, poskytnou implementace. V knihovně NeXT/Apple jsou protokoly často používány systémem distribuovaných objektů, aby reprezentovaly schopnosti objektu vykonávajícího na vzdáleném systému.,
syntaxe
@protocol NSLocking- (void)lock;- (void)unlock;@end
označuje, že existuje abstraktní myšlenka uzamčení. Tím, že uvádí v definici třídy, že protokol je implementován,
@interface NSLock : NSObject <NSLocking>// ...@end
instance NSLock tvrdí, že bude poskytovat implementaci dvě metody instance.
dynamické typingEdit
Objective-C, stejně jako Smalltalk, lze použít dynamické psaní: objekt může být odeslán zprávu, která není uvedena v jeho rozhraní., To může umožnit zvýšenou flexibilitu, protože umožňuje objektu „zachytit“ zprávu a odeslat zprávu jinému objektu, který může na zprávu odpovídajícím způsobem reagovat, nebo také odeslat zprávu jinému objektu. Toto chování je známé jako předávání zpráv nebo delegování (viz níže). Alternativně lze v případě, že zpráva nemůže být předána, použít obslužný program chyb. Pokud objekt nepředá zprávu, nereaguje na ni nebo zpracovává chybu,systém vygeneruje výjimku runtime., Pokud jsou zprávy odesílány do nil (ukazatel null object pointer), budou tiše ignorovány nebo zvýší obecnou výjimku v závislosti na možnostech kompilátoru.
statické informace o psaní mohou být také volitelně přidány do proměnných. Tyto informace jsou pak kontrolovány v době kompilace. V následujících čtyřech prohlášeních jsou poskytovány stále konkrétnější informace o typu. Příkazy jsou ekvivalentní za běhu, ale další informace umožňují kompilátoru varovat programátora, pokud předaný argument neodpovídá zadanému typu.,
- (void)setMyValue:(id)foo;
ve výše uvedeném prohlášení může být foo jakékoli třídy.
- (void)setMyValue:(id<NSCopying>)foo;
Ve výše uvedeném prohlášení, foo může být instance libovolné třídy, která odpovídá NSCopying
protokol.
- (void)setMyValue:(NSNumber *)foo;
ve výše uvedeném prohlášení musí být foo instancí třídy NSNumber.
- (void)setMyValue:(NSNumber<NSCopying> *)foo;
Ve výše uvedeném prohlášení, foo, musí být instance třídy NSNumber, a to musí odpovídat NSCopying
protokol.,
v Objective-C jsou všechny objekty reprezentovány jako ukazatele a statická inicializace není povolena. Nejjednodušším objektem je typ, na který id (objc_obj *) poukazuje, který má pouze ukazatel isa popisující jeho třídu. Jiné typy z C, jako jsou hodnoty a struktury, se nemění, protože nejsou součástí objektového systému. Toto rozhodnutí se liší od objektového modelu C++, kde jsou struktury a třídy sjednoceny.
ForwardingEdit
Objective-C umožňuje odesílání zprávy objektu, který nemusí reagovat., Spíše než reagovat nebo jednoduše upustit zprávu, objekt může předat zprávu objektu, který může reagovat. Přesměrování lze použít ke zjednodušení implementace určitých návrhových vzorů, jako je vzor pozorovatele nebo vzor proxy.
Objective-C runtime určuje dvojice metod v Objektu
objekt kteří chtějí realizovat předávání potřebuje pouze přepsat metodu přesměrování s novou metodou definovat přesměrování chování. Metoda akce performv:: nemusí být přepsána, protože tato metoda pouze provádí akci založenou na selektoru a argumentech., Upozornění SEL
typu, což je typ zpráv v Objective-C.
Poznámka: v OpenStep, Kakao, a GNUstep, běžně používaných rámců Objective-C, není použití Objektu třídy. – (Void) forwardInvocation: (NSInvocation *)anInvocation metoda třídy NSObject se používá k předávání.
ExampleEdit
zde je příklad programu, který demonstruje základy přesměrování.
zasílatel.speditér h.m příjemce.h
#import <objc/Object.h>// A simple Recipient object.@interface Recipient : Object- (id)hello;@end
příjemce.m
#import "Recipient.h"@implementation Recipient- (id)hello { printf("Recipient says hello!\n"); return self;}@end
main.,m
NotesEdit
Když zkompilovaný pomocí gcc kompilátoru zprávy:
kompilátor hlásí, že bod se dříve, že Dopravce neodpovídá hello zprávy. Za těchto okolností je bezpečné ignorovat varování od implementace přesměrování. Spuštění programu produkuje tento výstup:
$ ./a.outRecipient says hello!
CategoriesEdit
Při návrhu Objective-C, jedna z hlavních obav byla udržovatelnost velkých kód základny., Zkušenosti ze strukturovaného programovacího světa ukázaly, že jedním z hlavních způsobů, jak zlepšit kód, bylo rozdělit jej na menší kousky. Objective-C vypůjčil a rozšířil koncept kategorií z Smalltalk implementací pomoci s tímto procesem.
kromě toho jsou metody v rámci kategorie přidány do třídy za běhu. Kategorie tedy umožňují programátorovi přidávat metody do stávající třídy-otevřené třídy-bez nutnosti překompilovat tuto třídu nebo dokonce mít přístup ke zdrojovému kódu., Pokud například systém neobsahuje kontrolu pravopisu v jeho implementaci řetězce, mohl by být přidán bez úpravy zdrojového kódu řetězce.
metody v kategoriích se při spuštění programu nerozlišují od metod ve třídě. Kategorie má plný přístup ke všem proměnným instance v rámci třídy, včetně soukromých proměnných.
Pokud Kategorie deklaruje metodu se stejným podpisem metody jako existující metoda ve třídě, je přijata metoda Kategorie. Kategorie tak mohou nejen přidávat metody do třídy, ale také nahradit stávající metody., Tuto funkci lze použít k opravě chyb v jiných třídách přepisováním jejich metod nebo k globální změně chování třídy v rámci programu. Pokud mají dvě kategorie metody se stejným názvem, ale různými podpisy metod, není definováno, která metoda kategorie je přijata.
jiné jazyky se pokoušely tuto funkci přidat různými způsoby. TOM vzal systém Objective-C o krok dále a umožnil také přidání proměnných. Jiné jazyky Místo toho používaly řešení založená na prototypech, nejpozoruhodnější je já.
C# a Visual Basic.,Net languages implementují povrchně podobné funkce ve formě metod rozšíření, ale ty postrádají přístup k soukromým proměnným třídy. Ruby a několik dalších dynamických programovacích jazyků označují techniku jako „opičí záplatování“.
Logtalk implementuje koncept kategorií (jako první-třídy entit), které zahrne Objective-C kategorie funkce (Logtalk kategorií může být také použit jako jemnozrnné jednotek složení při definování např. nové třídy nebo prototypy; zejména, Logtalk kategorie může být prakticky dovážené libovolný počet tříd a prototypy).,
Příklad použití categoriesEdit
Tento příklad staví celé Číslo třídy, tím, že definuje první základní třídy s pouze přístupové metody implementovány, a přidáním dvou kategorií, Aritmetika a Zobrazení, které rozšiřují základní třídu. Zatímco kategorie přístup k základní třídě soukromé datové členy, často je dobré praxe, aby přístup k těmto členy soukromá data přes přístupové metody, která pomáhá udržet kategorií více nezávislých od základní třídy. Implementace takových doplňků je jedním z typických použití kategorií. Dalším je použití kategorií pro přidání metod do základní třídy., Nicméně, to není považováno za správnou praxi používat kategorie pro podtřídy overriding, také známý jako opice záplatování. Neformální protokoly jsou implementovány jako kategorie na základní třídě NSObject. Konvencí budou soubory obsahující Kategorie, které rozšiřují základní třídy, mít název BaseClass+ExtensionClass.h.
celé číslo.h
#import <objc/Object.h>@interface Integer : Object { int integer;}- (int)integer;- (id)integer:(int)_integer;@end
celé číslo.m celé číslo + aritmetika.h
#import "Integer.h"@interface Integer (Arithmetic)- (id) add: (Integer *) addend;- (id) sub: (Integer *) subtrahend;@end
celé číslo + aritmetika.m celé číslo + displej.h
#import "Integer.h"@interface Integer (Display)- (id) showstars;- (id) showint;@end
celé číslo + displej.m main.,m
NotesEdit
kompilace se provádí například:
gcc -x objective-c main.m Integer.m Integer+Arithmetic.m Integer+Display.m -lobjc
lze experimentovat vynecháním # import „celé číslo + aritmetika.h “ a řádky a vynechání celé číslo + aritmetika.m v kompilaci. Program bude stále spuštěn. To znamená, že je možné kombinovat přidané kategorie v případě potřeby; pokud Kategorie nemusí mít nějakou schopnost, jednoduše ji nelze sestavit.
PosingEdit
Objective-C umožňuje třídě zcela nahradit jinou třídu v rámci programu. Nahrazující třída se říká, že „představuje“ cílovou třídu.,
třída pózování byl prohlášen za zastaralý s Mac OS X v10. 5, a je k dispozici v 64-bit runtime. Podobné funkce lze dosáhnout použitím metody swizzling v kategoriích, která vymění implementaci jedné metody za jinou, která má stejný podpis.
u verzí, které stále podporují pózování, jsou všechny zprávy odeslané do cílové třídy místo toho přijímány představující třídou. Existuje několik omezení:
- třída může představovat pouze jednu ze svých přímých nebo nepřímých nadříd.,
- třída pózování nesmí definovat žádné nové proměnné instance, které v cílové třídě chybí (i když může definovat nebo přepsat metody).
- cílová třída možná neobdržela žádné zprávy před pózováním.
Pózování, podobně jako u kategorií, umožňuje globální rozšíření stávajících tříd. Pózování umožňuje dvě funkce, které chybí v kategoriích:
- a pózující třída může volat přepsané metody prostřednictvím super, čímž zahrnuje implementaci cílové třídy.
- třída pózování může přepsat metody definované v kategoriích.,
například
to zachycuje každé vyvolání setMainMenu k NSApplication.
#importEdit
v jazyce C směrnice#include
pre-compile vždy způsobí vložení obsahu souboru do zdroje v tomto bodě. Objective-C již #import
směrnice, což odpovídá kromě toho, že každý soubor je zahrnut pouze jednou za kompilace jednotky, zamezí nutnosti zahrnout stráže.