Подтвердить что ты не робот

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

Я хотел бы написать класс Objective-C без Cocoa или GNU Object.h (для образовательных целей). Я копался в сети, и мне кажется, что довольно много вещей, которые можно было бы ожидать "прийти с языком", таких как классы и отправка сообщений, фактически определены в файлах третьих сторон, таких как objc-runtime.h.

Есть ли какая-либо документация о том, что действительно является чистым Objective-C и что является частью среды выполнения? И какую функциональность я должен реализовать, чтобы получить рабочую среду без использования какого-либо стороннего кода, такого как Object.h или objc-runtime.h (еще раз обратите внимание, что это для образовательных целей, а не для производственного кода)?

Спасибо за понимание!

4b9b3361

Ответ 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