NSTouk – czyli Objective-C dla Javowca – Objective-C Runtime



NSTouk – czyli Objective-C dla Javowca – Objective-C Runtime

0 0


NSTouki

Prezentacja na warsztaty "NSTouk" - 17.01.14, Touk

On Github siejkowski / NSTouki

NSTouk

czyli Objective-C dla Javowca

I Ty już dziś możesz pisaćObjective-C!

NOTATKI do j2objc: Działa to całkiem nieźle. Javowe implementacje klas w objective-c. My dzisiaj też zabawimy się w takiego translatora.

Spotkały się pewnego razu dwie klasy...

Kolejność: - main.m: -> bardzo podobne do Javy -> nie ma namespaców -> @autoreleasepool - zarządzanie pamięcią -> @{coś} - słowo kluczowe w Obj-C, tłumaczone przez kompilator -> Objective-C - język kompilowany, Clang - kompilator dla Objective-C, oparty na LLVM -> wskaźnik - obiekty alokowane są na stercie, a na stosie tylko pointery -> Nawiasy kwadratowe - nie wywołuje się metod, ale wysyła wiadomości -> Dwa rodzaje wiadomości - instancyjne i klasowe - składa się to na konstruktor - GentleClass.h: -> Potrzebujemy dwóch klas - na klasę składają się dwa pliki -> Header jest publiczny, m jest prywatny -> NSObject - to jak object w Javie -> W m można klasy wewnętrzne tworzyć, ale tylko prywatne - brak zakresow oznacza inny, słabszy podział na prywatne i publiczne -> NSTouk-Prefix.pch - RespectedClass.h: -> możemy definiować protokoły wewnątrz headerów innych klas - zwykle tak się to robi -> protokół może meć @required i @optional -> Nazwy są przeplatane argumentami -> Argument jest podany w nazwie - konwencja, ale zawsze stosowana -> bardzo proste enumy - tylko integery w tle, ale za to mamy makra NS_ENUM i NS_OPTION - GentleClass.h: -> do implementacji protokołów - Plot.h: -> @class do zaznaczenia, że klasy będą dostępne po zlinkowaniu -> metoda klasowa plotWith... - Plot.m: -> wzorzec singletona -> gcd - dispatch once -> metoda klasowa plotWith... -> metoda instancyjna initWith... -> class extension - chowanie i nadpisywanie propertisów -> @property - setter/getter + ivar, a w zasadzie obietnica (@dynamic) -> konwencja syntezowanych ivarów - _ivar - Plot.m: -> blocki to domknięcia -> kopiują sobie wszystkie referencje, które są w nich wykorzystywane -> fucking block syntax - więc najczęściej typedef - main.m: - tutaj dopisujemy blocka - Plot.m: -> nervousConversationWithBlocking -> tworzenie i wywołanie blocka - uwaga na nil! -> nil to null, są też inne - adress nila to zawsze 0x0 - GentleClass.h: -> greetingsForDayTime -> z definicji większość typów jest immutable -> mutable też są dostępne, ale trzeba je implicite używać -> rozwlekłe nazwy metod - konwencja, ale wszyscy ją stosują -> stringByReplacingOccurencesOfString -> copy / mutableCopy - najszybszy i najprostrzy sposób na przejście mutable <-> imutable - RespectedClass.m: -> responseForGreetings - co to za (id) jako argument? -> id - object w objective c, dowolny - to jest dynamizm -> jak dynamizm, to introspekcja - isMemberOfClass -> nervousResponse -> kolekcje - NSArray, NSMutableArray, NSMutableIndexSet -> najpopularniejsza enumeracja - z użyciem bloku -> object literals - tablica[element] == [tablica setObject: atIndexedSubscript], jest też taki do słowników przez [slownik setObject:(id)obj forKeyedSubscript:] -> można sobie taką metodę napisać do dowolnek klasy - przydatne do tworzenia dsli -> fast enumeration prawie jak w javie - Plot.m: -> ternary operator w objective c i c block extensions - małe, przydatne sztuczki syntaktyczne - NSString+Calmness.h: -> kategorie to bardzo często wykorzystywany mechanizm -> można rozszerzać o kategorie klasy z biblioteki -> implementacja NSString jset rozbita na kategorie - NSString+Calmness.m: -> implementacja bardzo oczywista, kategoria ma dostęp do całego interfejsu klasy - w tym do ivarów, nawet prywatnych -> kategorie nie mogę nadpisywać metod już zdefiniowanych - coś się wywoła, ale nie ma gwarancji, co - undefined behavior -> kategorie są globalne - raz stworzysz, działa wszędzie Jak to jest zrobione?

Objective-C Runtime

Runtime to zwykła biblioteka w C dodająca do niego obiektowość siedzi w urządzeniu i jest linkowana dynamicznie otwarte źródła (yey!), ale koszmarne do czytania (makaron asseblera, makr i optymalizacji, warstwy kolejnych wstecznych kompatybilności) najbardziej interesujące są headery, a te są wszędzie dostępne - bo coś trzeba zaimportować przecież

obiektowość

typedef struct objc_class *Class;
typedef struct objc_object *id;

struct objc_object {
  uintptr_t isa;
  /* ivars */
}

struct objc_class : objc_object {
  Class superclass;
  /* cache, ivars description list, methods list */
}
to przybliżenie, bo obecnie runtime jest znacznie bardziej zoptymalizowany jeśli czas, to anegdotka o isa w 64 bitach objective c runtime 2.0 skrył wiele, ale koncepcja pozostała podobna cache, ivars list, method list - to wszystko struktury - wejść do runtime.h

[obj message];

objc_msgSend(obj, @selector(message));

@selector ?

objc_msgSend ma kilka wariantów i jest skrajnie zoptymalizowany - assembler z ręki czym jest selektor? - unikalna nazwa funkcji w scopie

- (NSString*)string:(NSString* string) { 
/* ... */ 
}

NSString* string(id self, 
                 SEL _cmd, 
                 NSString* string) 
{ 
  /* ... */ 
}

SEL _cmd ?

metody z dwukropkami tłumaczone są na podkreślniki

message forwarding

metody identyfikowane są w runtimie

wyjątek też pójdzie w runtimie

można dodać metodę w runtime, jeśli jej nie znaleziono, lub przerzucić ją do innego obiektu używane w proxy i w higher-order methods na przykład

dynamiczność

[object performSelector:@selector(selector)];

-(SEL)soMuchHigherOrderEatThisJava:(SEL) { /* ... */ }

[classes valueForKeyPath:@"method.chain.lol"];

method_exchangeImplementations(original, new);
method swizzling - technika wykorzystywana w testowaniu zwlaszcza i w mnóstwie mechanizmow z foundation

rozszerzalność

objc_allocateClassPair(Class superclass, 
                       const char *name, 
                       size_t extraBytes)

id objc_setAssociatedObject(id object, void *key);

class_addMethod(Class cls, SEL name, IMP imp, const char *types)
AssociatedObject jest fajny w połączeniu z kategoriami

refleksja

[object isMemberOfClass:[SomeClass class]];

[object isKindOfClass:[SomeClass class]];

[object conformsToProtocol:@protocol(SomeProtocol)];

[object respondsToSelector:@selector(SomeMethod)];

Method * class_copyMethodList(Class c, unsigned int *count)
introspekcja jest bardzo często używana tyle o runtime

zarządzanie pamięcią

konstruktor / destruktor

id object = [Class alloc];

Class object = [object init];

Class object = [Class new]; 
  (+ helpers like [NSArray array])

Class second = [object copy];

[object dealloc];

MRC vs ARC

[object retain];

[object release];

[object autorelease];

// ARC was here
reference counting jest super przez moment nawet garbage collector był, ale nie wszedł na długo

ARC vs bloki

self.myLovelyBlock = ^{
  [self whatever]; // OMG it's a cycle!
}

__weak typeof(self) bself = self;
self.myLovelyBlock = ^{
  [bself whatever]; // OMG it's weak!
}

[nil method] == nil // YES!
najgłębiej skrywana tajemnica iOSa

@property(strong, assign, atomic, readwrite)

@property(weak, unsafe_unretained, copy, assign, nonatomic, readonly)

Foundation / narzędzia

kolekcje

NSArray* / NSMutableArray*

NSDictionary* / NSMutableDictionary*

NSSet* / NSMutableSet*
immutable by default generalnie bardzo wydajne i dobrze zaimplementowane bardzo mało commonsów i zamienników

GCD

dispatch_sync / dispatch_async

dispatch_once

dispatch_after / dispatch_time

dispatch_queue_create / dispatch_get_main_queue
bardzo fajna rzecz, super proste api

makra

#define
nie ma magii, ale czasem się przydaje

powtórzenie

@interface

@implementation

@interface ( ... )

@protocol

@property

@dynamic

@selector

NSArray* / NSMutableArray*

NSDictionary* / NSMutableDictionary*

NSSet* / NSMutableSet*

NSString* / NSMutableString*

NSNumber *

@"", @1, @[], @{}, @(1 + 2)

źródła

pytania

podziękowania