2012-06-24 4 views
4

Я пытаюсь создать хороший инициализатор на основе блоков для класса object-c. Я объявляю его в суперклассе, и я хочу, чтобы он был полезен во всех подклассах.Динамическая модификация блока во время выполнения

Прямо сейчас у меня есть:

+ (id)createWithBlock:(void (^) (id newObject))creationBlock { 
    id newObject = [self object];  
    creationBlock(newObject); 
    return newObject; 
} 

который может быть использован (в подклассе), как, например:

Record *newRecord = [Record createWithBlock:^(id newObject) { 
    Record *newRecord = (Record *)newObject; 
    newRecord.name = @"Ginger"; 
    newRecord.type = @"Rhizome"; 
}]; 

Это нормально сейчас, но я хотел бы, чтобы это сравнению немного вниз. В идеале это выглядело бы так:

Record *newRecord = [Record createWithBlock:^{ 
    name = @"Ginger"; 
    type = @"Rhizome"; 
}]; 

Но это кажется немного амбициозным. Я также хотел бы быть в порядке только с:

Record *newRecord = [Record createWithBlock:^(Record *newRecord) { 
    newRecord.name = @"Ginger"; 
    newRecord.type = @"Rhizome"; 
}]; 

Эта последняя версия трудно, потому что кажется лязг делает некоторый тип проверки времени компиляции для блоков. Вышеупомянутое не будет компилироваться с определением createWithBlock: что у меня выше, потому что: incompatible block pointer types initializing 'void (^)(struct Record *)', expected 'void (^)(struct objc_object *).

Если он не сделал этого сильного типа проверки, я мог бы просто swizzle методы во время выполнения. (Или, может быть, я мог бы это сделать прямо сейчас, если бы я напечатал объявление в блоке?)

Я немного почесываю голову, и я прочитал почти каждый документ о блоках, которые я мог найти, в том числе спецификация clang. Если у кого-то есть идеи, которые я бы хотел их услышать, это для проекта с открытым исходным кодом, и я думаю, что эта модель принесет пользу всем пользователям с объективными-c.

Прямо сейчас мои мысли склоняются к imp_implementationWithBlock(). Но тогда мне нужно будет «построить» новый IMP, основанный на том, что в нем, и замените его. Реализуемое?

+0

Точно, что это достигается за просто инициализацию свойств * после * конструктора? (Независимо от того, что я просто проглотил подробный синтаксис, пока Apple не захочет добавить в ObjC дженерики, это идиома, которая не удивит людей, использующих ваш API.) – millimoose

+0

Это скорее стиль/читаемость, чем функциональность. Путем инициализации всего в блоке есть визуальное представление объекта, находящегося в одном месте на экране. И для более сложных инициализаций это мне кажется полезным. (Многие другие языки имеют такой тип создания). EDIT: Несколько других языков. –

+0

Возможно, вместо того, чтобы определять один инициализатор в суперклассе, вы можете заставить макрос препроцессора генерировать определение типов для третьего варианта синтаксиса для вас. Немного котельная, но кажется разумным немагическим компромиссом. – millimoose

ответ

3

Какой у вас компилятор? Я считаю, что последние версии LLVM будут принимать последний пример кода, который вы даете. (т. е. ошибка, которую вы даете, не должна происходить.)

В частности, это работает для меня с LLVM 3.1 в совершенно новом проекте Xcode в Xcode 4.3.3.

+0

Это очень полезно! Глупо, мой 'createWithBlock' компилировался с LLVM 3.1, и мое использование этого метода было скомпилировано с LLVM GCC 4.2. Переключился на новый компилятор, и он работает! Любые идеи для моего «идеального»? –

+0

Если вы действительно хотите уменьшить количество символов, все, что я могу придумать, это использовать макрос или использовать что-то вроде передачи var_args списка пар ключ-значение для установки. –

+0

Ну, у меня уже есть метод создания, который принимает NSDictionary. Я надеялся, что будет какой-то способ «осмотреть» блок и создать на нем новый блок? –

Смежные вопросы