O++C
4 subscribers
3 photos
6 links
Конспекты по книге "From C++ to ObjectiveC", а так же мои комментарии.
Download Telegram
Channel created
Книга начинается с того, что класс в Objective C - это объект, который в свою очередь является инстансом метакласса.

Где-то я такое слышал. Давайте разбираться.

Описание находится здесь:
www.cocoawithlove.com/2010/01/what-is-meta-class-in-objective-c.html

а перевод здесь:
https://habr.com/ru/post/207786/

Надо бы конечно это всё проверить, но у меня нет мака 😊 Пока качается хакинтош (vagrant init https://vagrant-osx.nyc3.digitaloceanspaces.com/osx-sierra-0.3.1.box), читаем дальше...
Ожидания относительно того, что в Objective C метаклассы похожм на те, что я видел в Python, не оправдались, по этому можно сказать, что моё "где-то сслышал" здесь совсем не применимо.

Понравилось базовое определение объекта:
typedef struct objc_object {
Class isa;
} *id;


Пока мне кажется что это очень гибко, когда любую структуру можно превратить в объект простым указателем на класс и после этого в рантайме добавить методы.

Наверно будет грубо сравнивать это с подходом в GO, но тем не менее, на мой взгляд, тут есть некоторые сходства, хоть в го и нельзясоздавать классы в рантайме.
Префикс NS используется почти для всех системных объектов. Это связано с тем, что... ох, это оказалась длинная история.

Итак, в Apple сделали API для MacOS, который называется Cocoa, который состоит из фреймворков Foundation Kit, Application Kit и Core Data.

Objective-C и Swift используются для создания приложений в Cocoa окружении. Кроме этих двух языков, можно использовать и другие, например Python, но не напрямую, а через дополнительные воркераунды и тулинги.

Основная часть Cocoa, а именно, App Kit и Foundation Kit - это продолжение фреймворков NeXTSTEP и OpenStep, которые разрабатывались для платформы NeXT, которую Apple купила в 1996м году.

Отсюда и префикс NS.
Еще интересная особенность: в языке есть одновременно nil и Nil.

nil - эквивалент NULL в качестве указателя на объект
Nil - эквивалент nil в качестве указателя на класс (на инстанс метакласса)

Nil и nil - НЕ взаимозаменяемы!
Сравнение объявления класса
public, private, protected
В Objective C методы моут быть только публичными. Обходной путь - написать реализацию, но не упомянуть в интерфейсе. А статических аттрибутов нет совсем.
Accessing instance variables inside a method
В Objective C нет перегрузки параметров в зависимости от типа :-( Обходной путь: называть иначе эти самые параметры, например:
...
- (int) g:(int) x y_int:(int) y;
- (int) g:(int) x y_float:(float) y;
...

y_int и y_float - это разные лейблы. То есть перегрузка как-бы есть и основана на названиях лейблов, а не на типах.
@selector - это новый тип, который является указателем на метод и является типом SEL.

В простом случае, вызов метода не совсем вызов, а отправка сообщения объекту, которая выглядит вот так:

[myObject someMethod];

Объекту myObject отправляется сообщение someMethod, однако эта конструкция будет преобразована компилятором в вызов функции с помощью того самого селектора:

objc_msgSend(myObject, @selector(someMethod));

Получить селектор можно двумя способами:
SEL aSelector = @selector(methodName);
SEL aSelector = NSSelectorFromString(@"methodName");


Разница в том, что первый способ работает на стадии компиляции, а второй в рантайме.

Интересно, что этот второй "рантаймовый" вариант, для создания селектора передаёт aSelectorName в функцию sel_registerName в виде строки. В свою очередь, sel_registerName работает как обычная С-функция:
SEL sel_registerName ( const char *str );

Вот еще интересная особенность.

Если у вас есть ДВА РАЗНЫХ объекта с одинаковым именем метода, то для его вызова будет использоваться идин и тот же селектор.

В общем случае, селектор - это обычная C-строка, которая сделана так, чтобы она не была совместима со строковыми типами и эмулирует несуществующий объект objc_selector.

Итого, можно вызывать метод как обычную функцию без всяких отправок сообщений:
SEL mySelector = sel_registerName("myMethod");
objc_msgSend(myObj, mySelector);


Материалы, которые помогли разобраться:
- https://habr.com/ru/post/250955/
В продолжении, давайте вызовем метод исключительно средствами языка C.

Для начала опишем класс:
#import <Foundation/Foundation.h>
#import <objc/runtime.h>

@interface TestClass : NSObject
@end

@implementation TestClass
+ (void)someClassMethod {
NSLog(@"Hello from some class method!");
}
- (void)someInstanceMethod {
NSLog(@"Hello from some instance method!");
}
@end


Определим селектор:
typedef void (*MyMethodType)(id, SEL);
Инстанцируем объект:
TestClass * myObj = [[TestClass alloc] init];


Как вызов метода выглядит в стиле языка C:
Class myObjClassObject = object_getClass(myObj);
Class myObjMetaclassObject = object_getClass(myObjClassObject);

MyMethodType instanceMethod = class_getMethodImplementation(myObjClassObject, @selector(someInstanceMethod));

MyMethodType classMethod = class_getMethodImplementation(myObjMetaclassObject, @selector(someClassMethod));

instanceMethod(myObj, @selector(someInstanceMethod));
classMethod(myObjClassObject, @selector(someClassMethod));


Как вызов метода выглядит в стиле языка Objective C:
[TestClass someClassMethod];
[myObj someInstanceMethod];


Материалы:
- https://habr.com/ru/post/250977/
NSObject category that allows you to easily map your objects to JSON and parse it back:

https://github.com/aperechnev/APJSONMapping
Протоколы

Используются для
- обхода отсутствия множественного наследования
- обязать класс реализовать методы

Описание протокола:

@protocol example
- (void) shouldBe;
@optional
- (void) canBeSkipped;
@required
- (NSInteger) shouldBeAlso;
@end


Использование в интерфейсе:
@interface MyObj: NSObject <example>
@end


Протоколы бывают формальные (formal) и неформальные (informal).
Есть такая интересная возможность в языке, как "категория", которая позволяет добавлять методы в класс без наследования.

Одной из таких категорий является informal protocol, только это категория объекта NSObject.

https://stackoverflow.com/questions/2183396/categories-vs-informal-protocols
Категории

Огромный класс можно разбить на категории. Это такой удобный способ создания God-objects. Для чего это нужно:
- категории можно компилировать независимо
- методы можно разделить на логические группы
- расширение существующих классов, не имея исходников

Хорошая статья с подробным расскажи о категориях:
https://adobkin.com/2012/08/11/katieghorii-v-objective-c/