Напишите класс Objective-C с нуля
Я хотел бы написать класс Objective-C без Cocoa или GNU Object.h
(для образовательных целей). Я копался в сети, и мне кажется, что довольно много вещей, которые можно было бы ожидать "прийти с языком", таких как классы и отправка сообщений, фактически определены в файлах третьих сторон, таких как objc-runtime.h
.
Есть ли какая-либо документация о том, что действительно является чистым Objective-C и что является частью среды выполнения? И какую функциональность я должен реализовать, чтобы получить рабочую среду без использования какого-либо стороннего кода, такого как Object.h
или objc-runtime.h
(еще раз обратите внимание, что это для образовательных целей, а не для производственного кода)?
Спасибо за понимание!
Ответы
Ответ 1
Действительно, единственное, что вам нужно позаботиться о себе, если вы не наследуете от NSObject
, - это создание и уничтожение объекта; методы иначе ведут себя одинаково, независимо от их родительского класса. Такие функции, как KVC и управление памятью, являются функциями OpenStep/Cocoa, но не требуются как часть языка.
Здесь класс с нуля:
@interface MyClass { // note the lack of a superclass here
@private Class isa;
}
+ (MyClass *)create;
- (void)destroy;
- (int)randomNumber;
@end
@implementation MyClass
+ (MyClass *)create {
return class_createInstance(self, 0);
}
- (void)destroy {
object_dispose(self);
}
- (int)randomNumber {
return rand();
}
@end
И вот как это можно использовать:
int main(int argc, char **argv) {
MyClass *foo = [MyClass create];
if (foo) {
printf("random! %i\n", [foo randomNumber]);
[foo destroy];
}
}
Изменить: Если вы даже не хотите использовать class_createInstance()
и object_dispose()
, вам придется реализовать эквиваленты вручную, а также эквивалент class_getInstanceSize()
, чтобы вы знали сколько памяти занимает объект. Но даже если вы справитесь с этим, не думайте, что вы сбежали из среды выполнения Objective-C! Рассылка сообщений по-прежнему полностью встроена в функции C во время выполнения, а синтаксис Objective-C преобразуется в вызовы этих функций во время компиляции.
Ответ 2
Мэтт Галлахер написал действительно классный пост при написании программы bare-bones Cocoa. Поскольку Objective-C является надмножеством C, вы можете просто сделать:
echo "int main(){return 0;}" | gcc -x objective-c -; ./a.out ; echo $?
В любом случае, вы, вероятно, получите много работы от чтения своего сообщения.
Ответ 3
Что касается исключения рамки и создания вашего собственного базового объекта, все, что вам нужно сделать, это убедиться, что первый iVar объявлен Class is_a
, и вы, вероятно, могли бы иметь разумный удар по репликации NSObject, перейдя к функции времени выполнения.
Что касается исключения библиотеки времени выполнения и рамки, это не реально. Цель C (или, по крайней мере, биты, которые не только C), является динамическим языком. Так что почти все, что он делает, что C не делает, обрабатывается библиотекой времени выполнения.
Возможно, вы сможете создавать свои собственные классы и объекты с использованием 32-битной среды выполнения и устаревшего API, который не абстрагирует макет классов, протоколов и т.д. в той мере, в какой это делает современная среда выполнения (я только реально ткнулись с современной средой выполнения)
Возможно, вы могли бы создавать классы, добавлять методы и выделять экземпляры и устанавливать значения в структурах class_t, а затем использовать malloc() для выделения, хотя даже тогда вы все равно будете неявно использовать функцию выполнения objc_msgSend каждый раз, когда вы используете Синтаксис [obj selector]
- если вы не хотите реализовать это также, и в этом случае вы просто переопределили язык самостоятельно. "Чистым ядром" языка, который вы ищете, является время выполнения.
Ответ 4
Здесь приведен пример класса без использования class_createInstance или object_dispose или любого другого Objective-C Runtime (по крайней мере, мы не вызываем их напрямую).
#import <objc/objc.h>
#import <stdio.h>
#import <stdlib.h>
#import <string.h>
static Class __scratchClass = NULL;
@interface Scratch {
Class isa;
char *name;
}
+ (id) initialize;
+ (Scratch*) new:(const char*)strName;
- (void) sayHello;
- (void) destroy;
@end
@implementation Scratch
+ (id) initialize {
__scratchClass = self;
return self;
}
+ (Scratch*) new:(const char*) strName {
Scratch* pObj = (Scratch*)malloc(sizeof(Scratch));
if (!pObj) return NULL;
memset(pObj, 0, sizeof(Scratch));
pObj->isa = __scratchClass;
pObj->name = (char*)malloc(strlen(strName)+1);
strcpy(pObj->name, strName);
return pObj;
}
- (void) sayHello {
printf("Hello, World!\nThis is Scratch (%s)...\n", name);
}
- (void) destroy {
if (name) {
free(name);
name = NULL;
}
free(self);
}
@end
int main(int argc, char** argv) {
Scratch* ps = [Scratch new:argv[0]];
[ps sayHello];
[ps destroy];
return 0;
}
Скомпилируйте код с (если вы сохраните его как "test1.m" ):
gcc -o test1 test1.m -lobjc