#objective-c
#objective-c
Вопрос:
Я хотел бы написать класс Objective-C без Cocoa или GNU Object.h
(в образовательных целях). Я покопался в сети, и мне кажется, что довольно много вещей, которые можно было бы ожидать «прийти с языком», таких как классы и отправка сообщений, на самом деле определены в файлах, написанных третьими сторонами, такими как objc-runtime.h
.
Есть ли какая-либо документация о том, что является действительно чистым Objective-C и что является частью среды выполнения / фреймворков? И какую функциональность я должен реализовать, чтобы получить рабочую среду без использования какого-либо стороннего кода, такого как Object.h
или objc-runtime.h
(еще раз обратите внимание, что это для образовательных целей, а не для производственного кода)?
Спасибо за любую информацию!
Комментарии:
1. Прочитайте этот ресурс от Колина Уилера. Речь идет не о создании пользовательского класса, а о том, как NSObject запутывает процесс привязки наших классов к среде выполнения.
Ответ №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! %in", [foo randomNumber]);
[foo destroy];
}
}
Редактировать: Если вы даже не хотите использовать class_createInstance()
и object_dispose()
, вам придется реализовать эквиваленты вручную, а также эквивалент class_getInstanceSize()
, чтобы вы знали, сколько памяти занимает объект. Но даже если вам это удастся, не думайте, что вы избежали среды выполнения Objective-C! Отправка сообщений по-прежнему полностью основана на функциях C во время выполнения, а синтаксис Objective-C преобразуется в вызовы этих функций во время компиляции.
Комментарии:
1. Ваш код требует включения
objc-runtime.h
(или какого-либо другого файла заголовка), который определяетclass_createInstance
иobject_dispose
. Я не хочу включать ничего, чего не написал сам.2. Вам нужны по крайней мере эти две функции, чтобы создать класс Objective-C, который может быть создан. Остальное необязательно.
3. @Jonathan Grynspan: Но эти методы должны быть где-то объявлены и реализованы, не так ли?
4. То же самое сделайте
objc_msgSend()
и с дюжиной других функций C во время выполнения.5. Итак, вы хотите создать свою собственную среду выполнения Objective-C и компилятор Objective-C? Вам также понадобится ваш собственный компилятор C, поскольку вы не хотите использовать какой-либо код GCC … 😉
Ответ №2:
Мэтт Галлахер написал действительно классный пост о написании простой программы Cocoa. Поскольку Objective-C является надмножеством C, вы можете просто сделать:
echo "int main(){return 0;}" | gcc -x objective-c -; ./a.out ; echo $?
В любом случае, вы, вероятно, многое получили бы от чтения его поста.
Комментарии:
1. Все его примеры программ (кроме той, которую вы опубликовали) используют код, написанный третьими сторонами (а именно
Object.h
иobjc-runtime.h
), который я не хочу использовать.
Ответ №3:
Что касается отказа от фреймворка и создания собственного базового объекта, все, что вам нужно сделать, это убедиться, что объявлен первый iVar Class is_a
и вы, вероятно, могли бы разумно попытаться воспроизвести NSObject, перейдя к функциям среды выполнения.
Что касается отказа от библиотеки времени выполнения И фреймворка, это на самом деле невозможно. Objective C (или, по крайней мере, те части, которые не являются просто C) — это динамический язык. Таким образом, практически все, что он делает, чего не делает C, обрабатывается библиотекой времени выполнения.
Возможно, будет возможно создавать ваши собственные классы и объекты, используя 32-разрядную среду выполнения и устаревший API, который не абстрагирует расположение классов, протоколов и т.д. в той степени, в какой это возможно в современной среде выполнения (я только по-настоящему поработал с современной средой выполнения)
Возможно, вы могли бы создавать классы, добавлять методы и выделять экземпляры, задавая значения в структурах class_t, а затем используя malloc() для выделения, хотя даже тогда вы все равно неявно использовали бы функцию времени выполнения objc_msgSend каждый раз, когда вы использовали [obj selector]
синтаксис — если только вы не хотите реализовать и это, в этом случае вы просто переопределили язык самостоятельно. «Чистое ядро» языка, который вы ищете, просто является средой выполнения.
Комментарии:
1. Ах, но он хочет знать, как это сделать без использования каких-либо функций времени выполнения. ;p
Ответ №4:
Вот пример класса, без использования class_createInstance или object_dispose, или любой другой среды выполнения Objective-C (по крайней мере, мы не вызываем их напрямую).
#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