Динамическая подгрузка xib интерфейсов на iPhone

написал Владимир Пузанов - October 16, 2008 – 15:19

Программам общего назначения может быть полезен механизм подгрузки скомпилированных xib прямо из сети. Я уже проводил эксперимент с динамическим меню (где в plist-файле описывалось древовидное меню и действия, вызываемые по разным пунктам). Сейчас захотелось попробовать полноценный динамический интерфейс.И так, приступим. Пример я писал на базе стандартного темплейта с UIView и его контроллером. Ключевой момент - в “самостоятельном” UIView я не нашел простого механизма получения полей. Таким образом, любой передаваемый нам по сети xib должен содержать не простой UIView, а его наследника - RootView.

В самом классе есть одно поле

NSMutableDictionary *fields;

И соответствующее ему read-only свойство:

@property (nonatomic,readonly,retain) NSDictionary *fields;

Главный фокус в том, что если создать поля в Interface Builder, то значения будут устанавливатся через великий и могучий KVC. Для начала засунем на нашу форму три UITextField и кнопку. Кнопка для простоты задачи будет завязана на действие в File’s Owner (суть наш контроллер), а для UITextField мы создадим три поля на RootView (не объявляя их в самом классе), и привяжем к ним соответствующие элементы:

Теперь реализуем основную магию RootView:

@synthesize fields;
 
- (void)setValue:(id)value forUndefinedKey:(NSString *)key
{
	if(!fields)
		fields = [[NSMutableDictionary alloc] init];
	[fields setObject:value forKey:key];
}
 
- (void)dealloc
{
	[fields release];
	[super dealloc];
}

С помощью этого нехитрого кода все “виртуальные” поля, описанные в IB попадают в наш словарь fields, который можно использовать в контроллере без прямых привязок:

- (IBAction)doCalculate
{
	UITextField *f1 = [[[self view] fields] objectForKey:@"field1"];
	UITextField *f2 = [[[self view] fields] objectForKey:@"field2"];
	UITextField *f3 = [[[self view] fields] objectForKey:@"field3"];
 
	f3.text = [NSString stringWithFormat:@"%d", [f1.text intValue] + [f2.text intValue]];
}
Вот собственно и все. Раскрытым остался вопрос, почему KVC не позволило мне сделать выборки вида

(gdb) print-object [[[self view] fields] valueForKey:@"field1.text"]
Cannot access memory at address 0x0
(gdb) print-object [[self view] valueForKey:@"fields.field1"]
Breakpoint 2, 0x965ffe17 in objc_exception_throw ()

Над этим еще стоит поразмыслить. Но, так или иначе, поставленная задача выполнена.

Обновлено. Что-то я запутался случайно, и перепутал valueForKey, и valueForKeyPath, получить текст поля можно сразу через

[[self view] valueForKeyPath:@"fields.field1.text"]

при этом не нужны никакие приведения к типам. Так же в принцие можно убрать свойство fields, KVC будет находить поле и по iVar.

Написать комментарий