2010-03-15 1 views
4

Я несколько компетентный рубиновый программист. Вчера я решил, наконец, попробовать свои силы с каркасами Apple Cocoa. Помогите мне увидеть вещи в ObjC?Строительство динамических классов в объекте C

Я пытаюсь окунуться в objc_allocateClassPair и objc_registerClassPair. Моя цель состоит в том, чтобы динамически генерировать несколько классов, а затем иметь возможность использовать их, как и любой другой класс. Это работает в Obj C?

Выделив и зарегистрировав класс A, я получаю ошибку компиляции при вызове [[A alloc] init]; (сказано, что 'A' Undeclared). Я могу создать экземпляр A с использованием метода objc_getClass времени выполнения. Есть ли способ рассказать компилятору о A и передать его сообщениям, как я бы NSString? Флаг компилятора или что-то еще?

У меня 10 или около того других классов (B, C, ...), все с тем же суперклассом. Я хочу сообщить их непосредственно в код ([A classMethod], [B classMethod], ...) без необходимости objc_getClass. Я пытаюсь быть слишком динамичным здесь или просто портить свою реализацию? Это выглядит примерно так ...

NSString *name = @"test"; 
Class newClass = objc_allocateClassPair([NSString class], [name UTF8String], 0); 
objc_registerClassPair(newClass); 

id a = [[objc_getClass("A") alloc] init]; 
NSLog(@"new class: %@ superclass: %@", a, [a superclass]); 
//[[A alloc] init]; blows up. 
+3

Возможно, было бы полезно, если бы вы уточнили, чего вы на самом деле пытаетесь достичь. В * большинстве * приложений использование сантехнических функций, таких как 'objc_registerClassPair' и' objc_getClass', может считаться * действительно * плохим признаком того, что вы делаете что-то неправильно. –

+3

Это довольно атипичный шаблон кодирования. Как правило, динамическое создание классов довольно ограничено в приложениях Objective-C. Большинство разработчиков больше сосредотачиваются на создании объектной модели, достаточно гибкой, чтобы содержать все необходимое. (Не сказать, что динамическое поколение классов - это всегда неправильный ответ - конечно, это хорошая забава для продолжения). – bbum

+0

Спасибо вам обоим. Я надеялся использовать порождать классы в цикле, чтобы сохранить себя, набирая их каждый из рук (DRY!), Но я найду другой путь. –

ответ

5

Причина, по которой [[A alloc] init]; взрывается в том, что компилятор не имеет понятия, что A средства. Компилятор никогда не знает, что есть A.

Edit: Кроме того, это выглядит как то, что вы хотите:

@interface A : NSObject { 
    NSString *myString; 
} 

- (id)initWithString:(NSString *)string; 

- (void)doItToIt; 

@end 

или, возможно,

@interface NSString (MyPrivateExtension) 

- (void)doItToIt; 

@end 
+1

Да, похоже, что нормальный путь работает лучше. В рубине сгенерированные классы ведут себя так же, как условно объявленные классы, и я надеялся, что я смогу получить тот же эффект здесь. –

+0

@kjell_: вы понимаете, что это два * дико * разных языка, да? –

+1

О, абсолютно. Но это не мешает мне свести к минимуму повторяющийся шаблонный код. –

1

Когда вы определяете класс на языке Objective-C, компилятор определяет Новый тип. Когда вы создаете класс динамически, компилятор не знает этого типа, поэтому ваш единственный выбор - использовать класс как id и динамически отправлять ему сообщения. Ruby - это динамически типизированный язык, который, вероятно, использует те же механизмы, что и компилятор при определении классов во время выполнения.

0

Посмотрите на сказочные F-Script и FSClass, которые могут это сделать и с открытым исходным кодом. FSClass определяет мета-класс, который может быть подклассифицирован во время выполнения.

Это делает работу с помощью objc_allocateClassPair и objc_registerClassPair но есть много других вещей происходит (за меня!), Что, вероятно, поможет.