Objective-C Állandók

Eredeti szerző Mike Ash. Fordította https://www.mikeash.com/pyblog/friday-qa-2012-06-22-objective-c-literals.html.

Üdv újra! Miután egy rövid kihagyás a WWDC, itt az ideje egy újabb őrült kaland. A mai téma az új objektum közvetlen használata erősen kerülendő szintaxis, hogy be Objective-C, amely által javasolt olvasó Frank McAuley.

Állandók

Bárki számára ismeretlen az a kifejezés, hogy összefüggésben programozási nyelvek “allandók” kifejezés bármely olyan érték, amely lehet írni közvetlenül a forráskód. Például, 42 egy szó a C (meg persze egy csomó más nyelven). Elég gyakori, hogy lásd, milyen értéket termelnek, a 42 egy egész literál, “hello” ez egy string literal, “x” egy karakter, szó szerint.

Közvetlen használata erősen kerülendő egy alapvető építőeleme a legtöbb programozási nyelvek, mivel ott kell, hogy legyen valami módja az írás állandó értékek kódot. Nem feltétlenül szükséges, mivel lehet építeni bármely kívánt érték futásidőben, de általában, hogy a kód egy sokkal szebb írni. Például építhetünk 42 használata nélkül, a közvetlen használata erősen kerülendő:

    int fortytwo(void)
    {
        static int zero; // statics are initialized to 0
        static int fortytwo;
        if(!fortytwo)
        {
            int one = ++zero;
            int two = one + one;
            int four = two * two;
            int eight = four * two;
            int thirtytwo = eight * four;
            fortytwo = thirtytwo + eight + two;
        }
        return fortytwo;
    }

Ha azonban az volt, hogy ezt minden egész használtuk, akkor valószínűleg mind feladni, számítógépes programozás, menj be egy szakma, ahol az eszközök nem utálom annyira. Hasonlóképpen lehetne építeni C szálakat kézzel ki a karaktert, de a húrok használják olyan gyakran, hogy a nyelv egy tömör formában írni őket.

A gyűjtemények nagyon gyakran használt is. C eredetileg nem volt lehetőség a gyűjtemény közvetlen használata erősen kerülendő, de a képesség, hogy a változók inicializálása egy összetett adattípus nagyon közel került:

    int array[] = { 1, 2, 3, 4, 5 };
    struct foo = { 99, "string" };

Ez nem mindig teljesen kényelmes, így C99 ki a vegyület közvetlen használata erősen kerülendő, amely lehetővé teszi az írásban olyan dolgok, közvetlenül a kód bárhol:

    DoWorkOnArray((int[]){ 1, 2, 3, 4, 5 });
    DoWorkOnStruct((struct foo){ 99, "string" });

Gyűjtemény közvetlen használata erősen kerülendő elég gyakori a más nyelveken is. Például a népszerű JSON sorozatkészítés formátum csak egy kodifikáció a JavaScript szó szintaxis. Ez a JSON kód is érvényes szintaxist, hogy hozzon létre egy sor szótárak a JavaScript, Python, valószínűleg egy másik nyelven:

    [{ "key": "obj" }, { "key": "obj2" }]

Egészen a közelmúltig Objective-C, nem szintaxis Objective-C gyűjtemények. Az egyenértékű a fent volt:

    [NSArray arrayWithObjects:
        [NSDictionary dictionaryWithObjectsAndKeys:
            @"obj", @"key", nil],
        [NSDictionary dictionaryWithObjectsAndKeys:
            @"obj2", @"key", nil],
        nil];

Ez nagyon bőbeszédű, olyan mértékben, hogy ez fájdalmas, hogy írja meg eltakarja, mi folyik itt. A korlátozások a C változó érv elhaladó is igényel null sentinel érték a végén minden tartály teremtés hívás, amely sikertelen lehet a rendkívül furcsa módon, amikor elfelejtett. Mindent összevetve, nem jó a helyzet.

Konténer Állandók

A legújabb bang most már támogatja a tartály közvetlen használata erősen kerülendő a Objective-C. A szintaxis hasonló a JSON, modern scripting nyelvek, de a hagyományos Objective-C @ dobott. A példa tömb/szótár így néz ki:

    @[@{ @"key" : @"obj" }, @{ @"key" : @"obj2" }]

Határozottan van egy kis @ túlterhelés történik itt, de ez egy hatalmas javulást jelent az előző állapot dolgokat. A @[] szintaxis létrehoz egy tömböt a tartalom, ami kell tárgyak. A @{} szintaxis létrehoz egy szótárt a tartalom, ami meg van írva, mint kulcs : érték helyett a teljesen nevetséges érték, kulcs szintaxis található a NSDictionary módszer.

Mert bele van építve a nyelvet, nem kell egy megszüntetéséről nulla. Sőt, a nulla bárhol ezek a közvetlen használata erősen kerülendő fog dobni egy hiba futásidőben, mivel Kakaó gyűjtemények hajlandó tartalmaznak nulla. Mint mindig, használja a [NSNull null] képviseletére nulla a gyűjtemények.

Nincs megfelelője szintaxisa NSSet. A tömb szó szintaktikai teszi a munkát egy kicsit kedvesebb, mivel tudsz valamit, mint a [NSSet setWithArray: @[ tartalom ]], de semmi sem olyan, mint a tömör szó szintaxis.

Mindent raktak bele egy ilyen tömb vagy szótár még mindig van, hogy egy tárgy. Nem lehet kitölteni egy tárgy tömb számokkal írásban @[ 1, 2, 3 ]. Ez azonban sokkal könnyebb a bevezetés….

Dobozos Kifejezések

Dobozos kifejezések lényegében lehetővé teszik a közvetlen használata erősen kerülendő megfelelő primitív típusok. A szintaxis @(tartalom), amely létrehoz egy objektumot boksz az eredménye, hogy a kifejezés a zárójelben.

Az objektum típusa attól függ, hogy milyen típusú kifejezés. Numerikus típusra konvertálni, hogy NSNumber tárgyakat. Például, @(3) termel egy NSNumber legalább 3, épp úgy, mintha te írtad [NSNumber numberWithInt: 3]. C húrok át NSString tárgyak segítségével az UTF-8 kódolás, @(“dolog”) termel egy NSString azok tartalmát.

Ezek tartalmazhatnak tetszőleges kifejezések, nem állandók, így azok túlmutatnak az egyszerű, közvetlen használata erősen kerülendő. Például, @(sqrt(2)), hogy készítsen egy NSNumber, amely a négyzetgyök 2. A kifejezés @(getenv(“FOO”)) egyenértékű [NSString stringWithUTF8String: getenv(“FOO”)].

Mint egy parancsikon, szám közvetlen használata erősen kerülendő lehet dobozos használata nélkül, a zárójel. Ahelyett, @(3), írd @3. Alkalmazott húrok, ez ad nekünk az ismerős, régi konstrukció @”objekt string”. Vegye figyelembe, hogy a kifejezések nem így működik. @2+2 @sqrt(2) előáll egy olyan hiba, meg kell parenthesized, mint @(2+2), valamint @(sqrt(2)).

Használja ezt, akkor könnyen létre egy objektumot tartalmazó tömb számok:

    @[ @1, @2, @3 ]

Még egyszer, egy kicsit @ túlterhelés, de sokkal szebb, mint az azonos, anélkül, hogy az új formával.

Vegye figyelembe, hogy a dobozos kifejezéseket csak akkor működik, numerikus típusok, char *, nem működik más mutatók vagy szerkezetek. Még mindig kénytelenek saját kézzel, a dobozt a NSRect, vagy SELs.

Tárgy Előfizetés

De várj, van még több is! Nincs egyszerűsített szintaxisa elragadó meg a beállítás elemet egy tömb szótár. Ez nem szorosan kapcsolódó objektum közvetlen használata erősen kerülendő, de megérkezett a clang ugyanakkor továbbra is az a téma, hogy könnyebb dolgozni, konténerek.

Az ismerős [] szintaxis a tömb hozzáférés most dolgozik NSArray tárgyak is:

    int carray[] = { 12, 99, 42 };
    NSArray *nsarray = @[ @12, @99, @42 ];

    carray[1]; // 99
    nsarray[1]; // @99

Működik a beállítási elemek változékony tömbök is:

    NSMutableArray *nsarray = [@[ @12, @99, @42 ] mutableCopy];
    nsarray[1] = @33; // now contains 12, 33, 42

Ne feledje azonban, hogy nem lehetséges, hogy a hozzáadás elemet, hogy egy sor erre, csak akkor cseréljük ki a meglévő elemeket. Ha a tömb index meghaladja a végén a tömb a tömb nem fog növekedni, hogy megfeleljen, hanem dob hiba.

Ez ugyanúgy működik, szótárak, kivéve az alsó index egy objektum kulcs helyett az index. Mivel a szótárak nincs indexelő korlátozások, ez is működik, a beállítás új bejegyzések:

    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
    dict[@"suspect"] = @"Colonel Mustard";
    dict[@"weapon"] = @"Candlestick";
    dict[@"room"] = @"Library";

    dict[@"weapon"]; // Candlestick

Mint a közvetlen használata erősen kerülendő, nincs ezzel egyenértékű jelölés NSSet, valószínűleg azért, mert nem sok értelme volt, hogy alsó index határozza meg.

Egyéni Előfizetés Módszerek

Egy nagyon jó húzás volt, a clang a fejlesztők a tárgy subscripting szereplők teljesen általános. Ők valójában nem kötve NSArray vagy NSDictionary semmilyen módon. Egyszerűen lefordítani, hogy egyszerű módszer, amely minden osztály végre.

Négy módszerek összesen: szetter egy getter az egész mutatják indexek, valamint egy szetter/getter a tárgy mutatják indexek. Az egész alsó index, mit akar ez a prototípus:

    - (id)objectAtIndexedSubscript: (NSUInteger)index;

Ezután végrehajtja-e ezt csinálni, amit akarsz, hogy támogassa a szemantika akarsz. A kód egyszerűen lefordítják mechanikusan:

    NSLog(@"%@", yourobj[99]);
    // becomes
    NSLog(@"%@", [yourobj objectAtIndexedSubscript: 99]);

A kód hozza az index a belső tömb, épít egy új objektum index alapján, jelentkezzen hiba, abort(), indítsd a játékot a-pong, vagy amit akarsz.

A megfelelő szetter van ez a prototípus:

    - (void)setObject: (id)obj atIndexedSubscript: (NSUInteger)index;

A mutatóujj, a tárgy, az, hogy ott van, csak meg kell tenni őket, hogy végre a szemantika akarsz. Ez megint csak egy egyszerű mechanikus fordítás:

    yourobj[12] = @"hello";
    // becomes
    [yourobj setObject: @"hello" atIndexedSubscript: 12];

A két módszer tárgy mutatják indexek hasonló. A prototípusok:

    - (id)objectForKeyedSubscript: (id)key;
    - (void)setObject: (id)obj forKeyedSubscript: (id)key;

Lehetséges, hogy végre mind a négy módszerek ugyanazon osztály. A fordító úgy dönt, melyiket hogy hívják, ha megvizsgáljuk, hogy milyen típusú alsó indexet. Egész mutatják indexek hívja a indexelt változatok, tárgyak, hívja a kulcsos változat.

Ez valójában csak egy kis részét üzemeltető túlterhelése már elérhető az Objective-C, amely hagyományosan teljesen elkerülni. Mint mindig óvatosan annak érdekében, hogy az egyéni megvalósítások továbbra is igaz, hogy a szellem a subscripting üzemeltető. Ne hajtsák végre a subscripting szintaxis hozzáfűzni tárgyak vagy üzenetet küldeni a hálózaton keresztül. Ha továbbra is akadályozza, hogy elragadó, majd egyre elemei a tárgy, a használat, a szintaxis marad következetes, akkor könnyen érthető, hogy milyen kódot csinál, anélkül, hogy tudom a részleteket.

Initializers

C van egy furcsa szokását, hogy minden initializer egy globális változó kell, hogy legyen egy fordítási időben állandó. Ez magában foglalja, az egyszerű kifejezéseket, de nem működik a hívásokat. Például, a következő globális változó nyilatkozat jogi:

    int x = 2 + 2;

De ez nem:

    float y = sin(M_PI);

C string közvetlen használata erősen kerülendő compile-time állandók, így ez a legális:

    char *cstring = "hello, world";

NSString közvetlen használata erősen kerülendő állandók, így a Cocoa ezzel egyenértékű jogi:

    NSString *nsstring = @"hello, world";

Fontos megjegyezni, hogy sem az új szó szintaktikai minősül fordítási időben állandó. Feltételezve, hogy a tömb egy globális változó, a következő nem jogi:

    NSArray *array = @[ @"one", @"two" ];

Ez azért van, mert a @[] szintaxis szó szerint azt jelenti, hogy egy hívást, hogy egy NSArray módszer. A fordító nem tudja kiszámítani az eredménye, hogy a módszer a fordítási időben, tehát ez nem egy jogi initializer ebben az összefüggésben.

Érdekes felfedezni, hogy pontosan miért is ez lenne a helyzet. A fordító meghatározza azokat a globális változókat a bináris, vannak betöltve közvetlenül a memóriába. A globális változók inicializálása, 2 + 2-es eredmények szerint a 4-es írva a memóriába. C string initializer eredmények a string tartalma íródik ki a program az adatokat, majd egy mutató, hogy azok tartalma íródik ki, mint a globális változó értékét.

Vegye figyelembe, hogy a C++, ezért Objective-C++, lehetővé teszi, hogy a nem-állandó initializers a globális változók. Amikor a C++ fordító találkozások ilyen kifejezés, a csomagot a funkció gondoskodik, hogy a funkció, hogy hívják, amikor a bináris betölti. Mert a initializer kód fut ilyen korán, lehet egy kicsit veszélyes használni, mivel más kód, mint NSArray lehet, hogy nem lesz kész. Mindenesetre, ha már láttam, hogy egy nem konstans initializer össze, majd kíváncsi, hogy miért, biztos, hogy kell összeállítani, mint a C++.

NSString közvetlen használata erősen kerülendő is compile-time állandók, mert a szoros csatolás között a fordító a könyvtárak. Van egy különleges NSString alosztály neve NSConstantString fix ivar elrendezés:

    @interface NSSimpleCString : NSString {
    @package
        char *bytes;
        int numBytes;
    #if __LP64__
        int _unused;
    #endif
    }
    @end

    @interface NSConstantString : NSSimpleCString
    @end

Csak tartalmaz egy isa (örökölt NSObject), a mutató byte, egy hosszú. Ha egy ilyen szó szerinti használják, mint egy globális változó initializer, a fordító egyszerűen írja ki a string tartalom, akkor azt írja ki ez az egyszerű tárgy szerkezete, végül inicializálja a globális változó egy mutatót, hogy a szerkezet.

Talán észrevetted, hogy nem kell tartani, illetve kiadás NSString közvetlen használata erősen kerülendő, mint más objektumok (bár ez még mindig egy jó ötlet, hogy így csak megszokásból). Sőt, el lehet engedni őket, ahányszor csak akarja, nem tesz semmit. Ez azért van, mert NSString közvetlen használata erősen kerülendő, nem dinamikusan kiosztott, mint a legtöbb Objective-C tárgyakat. Ehelyett ők osztják a fordítási időben, mint egy része a bináris, élni az életben, a folyamat.

Ez a szoros csatolás vannak előnyei, mint a termelő jogi globális változó initializers, nem igényel extra kód futtatását építeni a tárgy futásidőben. Van azonban egy nagy hátránya is. A NSConstantString elrendezés beállítása örökre. Az osztály fenn kell tartani pontosan, hogy az adatok elrendezését, mert az adatok elrendezése sütött a több ezer, harmadik féltől származó alkalmazások. Ha az Apple megváltoztatta az elrendezés, ezen harmadik féltől származó alkalmazások volna megtörni, mert tartalmaz NSConstantString tárgyak a régi elrendezés.

Ha NSArray közvetlen használata erősen kerülendő volt compile-time állandók, ott kell hogy legyen a hasonló NSConstantArray osztály rögzített elrendezés, hogy a fordító képes előállítani, fenn kellene tartani, külön-külön a többi NSArray implementációk. Ilyen kód nem fut a régebbi operációs rendszer, amely nem volt ez NSConstantArray osztály. Ugyanez a probléma a többi osztályokat, hogy az új közvetlen használata erősen kerülendő képes.

Ez különösen érdekes ebben az esetben, NSNumber közvetlen használata erősen kerülendő. Oroszlán bevezetett jelölt mutatók, amelyek lehetővé teszik egy NSNumber tartalmát, hogy a beágyazott közvetlenül a mutató, így nincs szükség a külön dinamikusan lefoglalt tárgy. Ha a fordító kibocsátott jelölt mutatók, a formátum nem változik, de a kompatibilitás a régi OS verziók. Ha a fordító kibocsátott állandó NSNumber tárgyakat, akkor NSNumber közvetlen használata erősen kerülendő lenne, lényegesen különbözik a többi NSNumbers, egy lehetséges jelentős teljesítmény hit.

Ehelyett a fordító egyszerűen bocsát ki, felhívja a keret, építése a tárgyak, pontosan olyan, mint tette volna kézzel. Ennek eredménye egy kicsit runtime hit, de nem rosszabb, mint az épület őket magad, anélkül, hogy az új szintaxis, sokkal tisztább design.

Kompatibilitás

Mikor elkezdjük használni ezt az új szintaxis? Xcode 4.3.3 a legújabb szállítási verzió még nem tartalmazza ezeket a kiegészítéseket. Tudunk ésszerűen várható, hogy a következő verzió, feltehetően jön a Mountain Lion tartalmazni fogja ezeket a változásokat a változata csenget.

Az OS rendszer kompatibilitás, a közvetlen használata erősen kerülendő egyszerűen létrehoz kód, amely felhívja a standard Cocoa initializers. Az eredmény megkülönböztethetetlen írni a kódot kézzel.

A történet subscripting egy kicsit bonyolultabb. Ezek a szükséges új módszerek, amelyek nem léteznek a Cocoa, ebben a pillanatban. Azonban a subscripting módszerek térkép közvetlenül a már meglévő NSArray, NSDictionary módszerek, így számíthatunk arra, hogy egy kompatibilitási shim hozzáférhetővé mentén a ARCLite shim, amely lehetővé teszi segítségével ARC a OSes amely megelőzi.

Következtetés

Az új objektum közvetlen használata erősen kerülendő, subscripting szintaxis az Objective-C jelentősen csökkentheti a bőbeszédűség kód foglalkozik erősen a tömbök, szótárak. A szintaxis hasonló megtalálta a közös scripting nyelvek, így a kód sokkal könnyebb írni, olvasni, eltekintve egy kis többlet @ szimbólumok.

 

 

Vissza a főoldalra

Leave a Reply

Your email address will not be published. Required fields are marked *