Статьи

Приложения для iOS с Tasty UI

В следующих нескольких главах этой серии мы собираемся создать приложение, которое поможет орнитологам-любителям выявлять и регистрировать птиц, с которыми они сталкиваются. Мы начнем очень просто и постепенно создадим приложение. Это серия Орни .

Настройка

Чтобы начать, откройте XCode и нажмите «Создать новый проект XCode» и, как в последнем уроке, выберите «Приложение на основе окна». На этот раз мы будем использовать встроенный в Xcode Interface Builder для создания пользовательского интерфейса.

Орни 1 Рисунок 1

фигура 1

На следующем экране дайте ему имя. Я называю свою «Орни», так что вы, вероятно, должны следовать за этим. Убедитесь, что для «Семейства устройств» установлено значение «Универсальный», и установите флажки «Использовать базовые данные» и «Включить юнит-тесты». В этот раз мы не собираемся ничего делать с CoreData и модульными тестами, но в следующем уроке мы расскажем: план состоит в том, что мы будем продолжать модифицировать это приложение по мере продолжения серии, пока у нас не появится что-то, что могло бы быть гипотетически выпущенный!

Создание универсального приложения означает, что оно будет работать как на iPhone, так и на iPad. Создание пользовательского интерфейса, подходящего для обоих семейств устройств, требует гораздо больших усилий, поскольку обычно это означает создание двух отдельных пользовательских интерфейсов на основе одних и тех же контроллеров.

Орни 1 Рисунок 2

фигура 2

Нажмите «Далее» и Xcode сгенерирует ваше приложение.

Ваши многоцветные приложения-делегаты

Хорошо. Это как раньше, но по-другому! Вы заметите, что теперь у вас есть не один, а три приложения AppDelegate, а именно OrnyAppDelegate , OrnyAppDelegate_iPhone и OrnyAppDelegate_iPad . Whoah! В чем дело!?

Орни 1 Рисунок 3

Рисунок 3

Помните, что мы сделали это приложение универсальным. Xcode не знает заранее, на каком устройстве будет работать это приложение, поэтому оно дает каждому устройству отдельную точку входа в ваш код. На iPhone работает OrnyAppDelegate_iPhone , а на iPad — OrnyAppDelegate_iPad . Это означает, что вы можете реализовать совершенно разные ViewControllers и Views для каждого устройства.

«Но подожди!», — возражает ты, услужливо: «Разумеется, это означает, что я должен удвоить работу?»

Не так, нежный разработчик! Ваши два AppDelegates для конкретного устройства наследуют функциональность от вашего класса OrnyAppDelegate . Это означает, что любой код, который вы пишете в OrnyAppDelegate , также присутствует в OrnyAppDelegate_iPhone и OrnyAppDelegate_iPad . Бесплатно.

Конечно, вы можете переопределить метод в своем базовом классе OrnyAppDelegate , только для версии для iPad. Вы также можете сделать это, потому что любые сообщения, реализованные в OrnyAppDelegate_iPad или OrnyAppDelegate_iPhone будут переопределять сообщения с одинаковой подписью (именем и аргументами) на родительском OrnyAppDelegate_iPhone .

Вы можете увидеть, где мы объявляем один класс родительским для другого в строке 12 OrnyAppDelegate_iPhone.h :

 @interface OrnyAppDelegate_iPhone : OrnyAppDelegate { } 

Этот @interface OrnyAppDelegate_iPhone : OrnyAppDelegate примерно переводится, чтобы позволить существовать классу с именем OrnyAppDelegate_iPhone который является дочерним (то есть наследует функциональность от) OrnyAppDelegate .

XIB файлы

У вас также есть несколько файлов XIB, MainWindow_iPhone.xib и MainWindow_iPad.xib . XIB-файлы представляют собой представление Xcode для View, они, по сути, являются пользовательским интерфейсом вашего приложения.

Если вы нажмете на одну, вы откроете редактор интерфейса. Мы собираемся изучить эту точку зрения на мгновение.

Орни 1 Рисунок 4

Рисунок 4

Один ViewController для обслуживания всех

Первое, что мы хотим, чтобы наше приложение было в состоянии сделать, это отобразить список местных видов птиц. Мы собираемся создать структуру данных, которая будет содержать информацию, которую мы хотим отобразить, а затем использовать UITableView, чтобы отобразить их пользователю.

Создайте BirdListViewController

Давайте добавим ViewController. Мы собираемся поделиться этим между двумя AppDelegates и двумя семействами устройств, потому что мы можем это сделать.

Нажмите «Файл> Новый файл» или нажмите «Command + N».

Орни 1 Рисунок 5

Рисунок 5

Выберите «UIViewController».

Орни 1 Рисунок 6

Рисунок 6

Оставьте для поля подкласса значение UIViewController, но убедитесь, что установлен флажок «С XIB для интерфейса пользователя». Мы хотим этого!

Введите «BirdListViewController» в поле «Сохранить как» и нажмите «Сохранить». Убедитесь, что вы сохраняете в проект «Orny» и в папку или группу, также называемую «Orny», с целью по умолчанию для приложения «Orny».

Теперь у вас должно быть 3 дополнительных файла:

  • заголовочный файл, BirdListViewController.h
  • файл сообщения, BirdListViewController.m
  • файл BirdListViewController.xib , BirdListViewController.xib

Ницца!

Подготовка наших данных

Нам нужна структура для хранения данных, которые мы хотим показать пользователю. Мы собираемся создать вложенную структуру данных в нашем BirdListViewController , NSArray, содержащем NSDictionary!

Сделайте так, чтобы ваш BirdListViewContoller.h выглядел следующим образом:

 @interface BirdListViewController : UIViewController { } - (void)loadBirdData; @property (nonatomic, retain) NSMutableArray *birds; @end 

Мы добавили сигнатуру метода - (void)loadBirdData и @property .

Помните — нам нужно @synthesize наших @properties , поэтому добавьте в BirdListViewController.m после объявления @implementation следующую строку кода: @synthesize birds;

Далее вниз по файлу (где-то ближе к концу) добавьте следующую реализацию сообщения в BirdListViewController.m :

 #pragma mark UITableViewDataSource methods - (void)loadBirdData { birds = [[NSMutableArray alloc] init]; // Add a Magpie to our bird array [birds addObject: [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:@"Magpie", @"magpie.jpg", @"Black and white and crafty all over!", nil] forKeys:[NSArray arrayWithObjects:@"name", @"image", @"description", nil] ] ]; // And another! [birds addObject: [NSDictionary dictionaryWithObjects: [NSArray arrayWithObjects:@"Rosella", @"rosella.jpg", @"A red and blue parrot", nil] forKeys:[NSArray arrayWithObjects:@"name", @"image", @"description", nil] ] ]; } 

#pragma mark определяет для нас «примечание» о следующем коде; это как комментарий, но он может использоваться Xcode для закладки разделов нашего кода.

Мы выделили память и NSMutableArray экземпляр нашего свойства birds как NSMutableArray . Массив представляет коллекцию объектов. NSArray является неизменным, то есть, когда он создается, он содержит все, что вы добавляете в него с помощью метода создания экземпляров, такого как initWithObjects . После этого вы не можете добавлять или удалять элементы.

Напротив, NSMutableArray является динамическим и может иметь большое количество объектов, добавляемых к нему динамически, в пределах ограничений памяти устройства.

Мы добавляем два объекта к нашим NSMutableArray birds оба из которых являются NSDictionaries . Словарь — это набор пар ключ-значение, например ассоциативный массив в PHP. NSDictionary , как и NSArray , является неизменным, но у него есть подкласс NSMutableDictionary , который можно изменить после создания.

Вы можете видеть, что мы добавляем еще один массив в словарь, содержащий значения, на которые мы хотим, чтобы словарь ссылался. Затем мы передаем другой массив, содержащий ключи, которые мы хотим ссылаться на эти значения. Положение ключа в его массиве (имя, изображение, описание в списке) соответствует положению значения, которое он представляет (@ ”Mapie”, @ ”magpie.jpg”, @ ”Черно-белое и хитрое во всем! «)

Все значения, которые мы добавляем, являются строками. В Objective-C мы обозначаем строку, используя @ -символ, @"like this" .

В качестве заключительного замечания об этой функции, мы заканчиваем любой список объектов знаком ‘nil’, чтобы дать объекту, который мы передаем список, знать: «Эй, этот список уже готов».

На память и утечки

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

Статья Эндрю Маркхэма об управлении памятью в iPhone дает краткое изложение вопросов управления памятью, но чтобы быть кратким и приятным, нам нужно выпустить то, что мы выделяем. Итак, сделайте так, чтобы BirdListViewController.m выглядел так:

 - (void)dealloc { [birds release]; [super dealloc]; } 

Почти сделано здесь!

Пробуждение

Мы определили сообщение, чтобы создать нашу структуру данных и сохранить ее, но до сих пор мы ее не вызывали. Код никогда не будет выполнен!

Наш ViewController будет запущен другим объектом, в данном случае, окном нашего приложения. Нам нужен какой-то способ для вызова нашего метода, когда это происходит, и этот метод известен как awakeFromNib .

Добавьте следующий код в ваш метод initWithNibName :

 - (void)awakeFromNib { [self loadBirdData]; } 

Редактировать вид

Теперь мы хотим отредактировать наш XIB-файл и добавить UITableView. Нажмите на BirdListViewController.xib .

Орни 1 Рисунок 7

Рисунок 7

Если вы не видите панели Utilities справа, как на рисунке 7, представьте их, используя крайнюю правую из трех кнопок «View», расположенных в правой верхней части интерфейса Xcode.

Сначала выберите объект «Владелец файла» из списка «Объекты» слева от редактора, который выглядит как прозрачный 3D-блок. Откройте меню Outlets, щелкнув правой кнопкой мыши по объекту, и нарисуйте линию от круга справа от «View» к вашему UIView, который представляет собой большое белое пространство с рамкой вокруг него.

Эти значки в левой части редактора интерфейса обычно представляют «соединения» с объектами кода. Они не являются собственными объектами кода, они являются указателями на некоторый произвольный фрагмент кода, который вы можете определить и переопределить. Когда приложение запускается, iOS знает, что с ними делать.

Затем в браузере объектов, расположенном в нижней части панели «Утилиты», выберите «UITableView» и перетащите его на белый «вид», расположенный в середине редактора интерфейса.

Нажмите на таблицу, чтобы выбрать ее, а затем нажмите стрелку вправо в верхней части самой правой панели инструментов, которая является инспектором соединений на панели «Утилиты». Там вы увидите выходы для «UITableView», который мы только что добавили. Обратите внимание, что вы также можете щелкнуть правой кнопкой мыши «UITableView», чтобы открыть похожее меню.

Орни 1 Рисунок 8

Рисунок 8

Наведите курсор мыши на круг справа от «источника данных» в Outlets. Нажмите и перетащите, чтобы нарисовать линию на всем пути к «Владельцу файла», который, как вы помните, представляет собой прозрачную трехмерную рамку, как показано на рисунке 9. Теперь вы сказали «UITableView» извлечь данные из вашего « BirdListViewController. Уф!

Орни 1 Рисунок 9

Рисунок 9

Этикет и протокол

UITableView нужен любой объект, связанный с ним как «источник данных», чтобы соответствовать протоколу. Это контракт между объектами, в котором говорится, что они поддерживают и ожидают реализации определенных методов.

Нам нужно указать, что наш ‘BirdListViewController’ намеревается соответствовать протоколу ‘UITableViewDataSource’, поэтому измените его определение в BirdListViewController.h чтобы он выглядел так:

 @interface BirdListViewController : UIViewController <UITableViewDataSource> { } ... 

Намерения только дают нам пока, мы также должны реализовать некоторые методы, чтобы поддержать наше требование поддержки протокола. Добавьте следующий код в BirdListViewController.m внизу, где мы остановились раньше:

 - (NSInteger)tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section { return [birds count]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *newCell = [[[UITableViewCell alloc] init] autorelease]; NSDictionary *thisBird = [birds objectAtIndex:[indexPath row]]; UILabel *newCellLabel = [newCell textLabel]; [newCellLabel setText:[thisBird objectForKey:@"name"]]; return newCell; } // fixed font style. use custom view (UILabel) if you want something different - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { return @"Some Birds"; } 

Протокол определяет как обязательные, так и необязательные методы. Здесь мы реализуем только необходимые методы, и наш cellForRowAtIndexPath может использовать некоторые улучшения, но мы должны рассмотреть эти элементы более подробно в следующей статье.

Почти! Почти!

Мы почти у цели.

Последнее, что нам нужно сделать, это установить ‘rootViewController’ нашего iPad и iPhone ‘UIWindows’. Повторите следующие шаги для MainWindow_iPhone.xib и MainWindow_iPad.xib :

  1. Откройте соответствующий файл XIB.
  2. Выберите UIViewController из библиотеки объектов.
  3. Перетащите его в список объектов, значки слева от редактора.
  4. Выберите UIViewController и на панели «Служебные программы» щелкните третий значок слева, который представляет собой пользовательский класс и панель удостоверений.
  5. Измените имя класса на «BirdListViewController».
  6. Нажмите на Окно, очень простой белый квадрат в значках слева от Редактора интерфейса, снова щелкните правой кнопкой мыши, чтобы отобразить его Розетки.
  7. Перетащите и нарисуйте линию от круга справа от выхода «rootViewController» до объекта «BirdListViewController» в списке слева.

Шаги с 1 по 6 показаны на рисунке 12, вы можете увидеть, что «UIViewController» выделен в правом нижнем углу библиотеки объектов, новое имя класса вверху в Identity Inspector и результирующий «Bird List View Controller» указан ,

Орни 1 Рисунок 10

Рисунок 10

Также обратите внимание на простой белый значок «Окно», который подключен к «Контроллеру представления списка птиц» в шагах 6 и 7. И вы помните, что это необходимо сделать для файлов iPhone и iPad XIB, верно? Уф!

Выполнить! Выполнить!

Хит Беги. Вы должны увидеть «UITableView», заполненный нашими двумя строками, содержащими Сороку и Розеллу. Вы можете вернуться из симулятора обратно в XCode, выбрать другой симулятор и снова выполнить горячий запуск, чтобы протестировать оба устройства.

Мы закончили для этой главы. Мы рассмотрели создание универсального приложения, управляющего данными в одном ViewController и редактирующего View, и, наконец, использующего его как для iPhone, так и для iPad. В следующий раз мы рассмотрим добавление интерактивности!

Серия «Орни»

С условием наличия вкусного освежающего напитка в руках, используйте метку для всех статей Орни , или прыгайте прямо в статью специально из этого индекса.