Написать класс Objective-C с нуля

#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