Текст — Пишем первое приложение для iPhone

После просмотра видео урока о создании нашего первого приложения, будет очень полезно более подробно разобрать принцип написания приложений для iPhone. Что я и предлагаю вам сделать в следующем уроке.

Введение

В этом обучающем материале я дам Вам краткое введение о том, как начать писать своё первое iPhone приложение. Для начала Вам потребуется последняя версия iPhone SDK, которую можно загрузить с официального сайта Apple. С SDK Вы получаете некоторые сервисные программы, такие как Xcode, Interface Builder (конструктор интерфейса), iPhone simulator (симулятор iPhone) и многие другие. Первое приложение обычно называют “Hello World”, но я назвал своё первое приложение “Hello Universe”, потому как революционное устройство требует смены имени.

Цель приложения “Hello Universe”

Используя это приложение, пользователь сможет ввести его/ее полное имя и, нажав на соответствующую кнопку, увидеть появившееся сообщение вида “John Doe says Hello Universe!!!” (Джон До говорит Привет Вселенной!!!). Данное приложение даст Вам не только представление о некоторых сервисных программах, но также покажет, как можно использовать средства управления, отвечать на события и создавать новые визуальные объекты.

Вот так будет выглядеть приложение (рис. 1):

Создание нового проекта

Запустите Xcode и нажмите на File -> New Project -> Select Application (под iPhone OS)-> select Window-Based Application и кликните на Choose (рис. 2):

Далее Вас попросят сохранить Ваш проект и дать ему название. Xcode создает некоторые файлы для нас, основанные на названии проекта, таким образом Вам необходимо быть внимательными с названием, которое вы даёте. Я назвал свой проект “HelloUniverse“. Так выглядит список файлов в Xcode (рис. 3):

Все файлы класса  хранятся в папке “Classes”  («Классы»), некоторые специальные файлы числятся в разделе  “Other Sources” («Другие ресурсы»), все файлы изображений и различные ресурсы располагаются в папке “Resources” («Ресурсы»), и любая библиотека или структура, добавляемая в наш проект, обозначена в папке “Frameworks”  («Инфраструктура»), Очень важно сохранять все рисунки, файлы, базы данных, и различные виды отображения информации на экране в папке “Resources” («Ресурсы»), потому что все iPhone приложения работают в её собственной «песочнице» ; это означает, что они (приложения) могут обращаться только к файлам, помещенным в папку ресурсов.

Как запускается приложение

Каждый C/C ++/Java/C# программист знает об основном методе , который используется в файле main.m, лежащем в папке “Other Sources“. Вам, собственно, никогда не придётся изменять этот метод и всё, что мы должны знать, это то, что этот метод отвечает за запуск приложения. Когда приложение запускается на устройстве или симуляторе, запрашивается метод applicationDidFinishLaunching. Метод определен в файле “HelloUniverseAppDelegate.m“, который может быть найден в папке “Classes“.

Конструктор интерфейса

Используя конструктор интерфейса, мы можем проектировать наше приложение, добавляя средства управления или создавая дополнительные виды отображения информации на экране.  Файлы, которые создает конструктор, сохраняются с расширением .xib и называются nib файлами. Каждый проект получает один nib файл, за вызовом которого следует вызов “MainWindow.xib” из папки “Resources“. iPhone приложение имеет лишь одно окно (MainWindow.xib) в отличие от настольного приложения, которое создаётся с большим количеством окон; тем не менее, мы можем создавать множество видов отображения информации на экране, которые добавляются к окну. Двойной щелчок на “MainWindow.xib” запустит конструктор интерфейса, который откроет четыре окна, и одно из окон будет выглядеть следующим образом (рис. 4):

Изображение выше показывает содержимое nib файла “MainWindow.xib“. В каждом nib файле есть по крайней мере два файла: File’s Owner и First Responder, которые невозможно удалить. Любые объекты кроме первых двух, представляют собой экземпляр класса , который создаётся при загрузке nib файла. File’s Owner указывает на то, что ему принадлежит объект в nib файле. First Responder говорит нам, с каким именно объектом мы в данный момент взаимодействуем: текст, кнопки и т.д. Третий объект, который является особенным для файла MainWindow.xib, называют “Hello Universe App Delegate” и этот файл представляет класс “HelloUniverseAppDelegate“. Последний представляет объект, который мы проектируем в наших приложениях.

Создание нового вида отображения на экране

Если бы мы создавали этот проект, используя шаблон проекта “View-Based Application” тогда не было бы необходимости создания другого вида с нуля, что не так забавно, как в нашем случае. В конструкторе интерфейса создайте новый вид через File -> New -> Select Cocoa Touch -> View и нажмите Choose. Давайте сохраним этот вид в проектной папке, называя его “HelloUniverse“, и как только мы делаем это, IB (Interface Builder) запросит нас добавить вид к текущему проекту; нажмите “Add“, и это отобразится в Xcode. А теперь переместите вид в папку “Resources”.

Создание контроллера вида

Итак, у нас есть вид, теперь давайте создадим контроллер вида, с помощью которого можно будет управлять этим видом. В Xcode создайте новый контроллер вида путём выбора классов и нажатием File -> New File -> Select Cocoa Touch Classes under iPhone OS -> select UIViewController -> кликните на Choose и назовите ваш файл “HelloUniverseController“, не изменяя расширения. Только что созданный класс наследует от UIViewController, который знает, как взаимодействовать с видом. Теперь, когда у нас есть вид и класс контроллера, должен быть некоторый способ соединить эти два файла, и мы можем сделать это, устанавливая класс собственностью File’s Owner. Кликните дважды на файл “HelloUniverse.xib” в Xcode, чтобы запустить конструктор интерфейса (interface builder), затем выберите File’s Owner -> select Tools -> Identity Inspector и в категории “Class Identity” смените класс на “HelloUniverseController“. Так должна выглядеть тождественность класса (рис. 5):

Как только это будет выполнено, нам понадобится способ управления видом в nib файле непосредственно из кода, и это обеспечивается через связь переменной экземпляра класса вида с объектом вида в nib файле. Связь достигается путём использования “outlets“. Выберите Tools -> Connections Inspector и создайте связь между переменной вида и видом в nib файле. А теперь подвигайте мышью в пустой области, чтобы увидеть, как она сменяется на символ «+», указывая, что связь может быть установлена. Кликните на эту область, перенесите мышью на вид в nib файле и отпустите. Выполняя это, вы будете видеть голубую линию, простирающуюся от области до мыши. Как только связь будет создана, инспектор связей для File’s Owner будет выглядеть так (рис. 6):

Добавление средств управления к виду

По скриношту выше видно, что нам нужны два текстовых поля, одна метка и кнопка (Round Rect Button). Из библиотеки перетаскиваем средства управления на вид и выравниваем так, как показано на рисунке 1. После того, как вы добавили средства управления, давайте изменим некоторые из их свойств, начиная с текстовых полей. Выберите первое текстовое поле и откройте Attributes Inspector через  Tools -> Attributes Inspector. Под указателем введите “First Name“, под “Text Input Traits” смените на свойство Capitalize для “Words“, а также измените свойство the Return key на “Done“. Примените те же настройки и для другого текстового поля, но смените там в указателе фразу на “Last name“. Выберите метку и удалите её текстовые свойства, так как мы не хотим, чтобы метка говорила что-либо до тех пор, пока не нажата кнопка. Кликните дважды на кнопку, чтобы исправить заголовок кнопки и впечатайте “Click Me”. Сохраните всё и закройте Interface Builder, так как мы успешно закончили проектирование вида.

Соединение экземпляров переменных к объектам в виде

Нам всё ещё нужен способ взаимодействия со средствами управления вида и в коде. Тут то нас и выручают outlets. IBOutlet – это специальное ключевое слово, при использовании которого с экземпляром переменной, в Interface Builder появляется переменная. Так как IBOutlet заставляет переменную появиться в Interface Builder, используя IBAction в качестве типа результата (возвращаемый тип), то в случае метода, то он будет демонстрировать противоположный эффект. Используя IBAction, мы можем обработать событие, которое будет запускаться любым элементом управления, расположенным в виде. Давайте посмотрим как это работает. Откройте файл HelloUniverseController.h в Xcode и впечатайте следующий код:

//HelloUniverseController.h
@interface HelloUniverseController : UIViewController {
IBOutlet UITextField *txtFirstName;
IBOutlet UITextField *txtLastName;
IBOutlet UILabel *lblMessage;
}
- (IBAction) btnClickMe_Clicked:(id)sender;
@end

//HelloUniverseController.m
- (void)dealloc {
[txtFirstName release];
[txtLastName release];
[lblMessage release];
[super dealloc];
}

Все переменные свыше отмечены IBOutlet, и Interface Builder сделает их доступными для себя, чтобы могли быть сделаны все надлежащие связи. У нас также есть метод, тип результата (возвращаемый тип) которого — IBAction (void); Interface Builder также сделает этот метод доступным для себя так, чтобы мы могли выбрать, какое из событий вызовет этот метод. Метод также принимает параметр, именуемый “sender“, который является объектом, вызывающим (запускающим) событие. Переменные располагаются в dealloc методе как показано выше. Давайте соединим эти экземпляры класса переменных со средствами управления вида (HelloUniverse) как было описано ранее. Откройте Interface Builder двумя кликами по файлу HelloUniverse.xib и выберите File’s Owner, откройте Connections Inspector, чтобы увидеть все переменные, представленные под Outlets, и чтобы создать связь (рис. 7):

Давайте соединим событие нажатия кнопки с методом “btnClickMe_Clicked“. Выберите кнопку, и под списком Events окажется, что у нас нет события нажатия кнопки; однако, мы имеем событие “Touch Up Inside“, которое переводится на передний план, когда кнопка нажата и отпущена, символизируя клик. Выбрав кнопку, кликните по области рядом с “Touch Up Inside” и перетащите вашу мышь на File’s Owner и отпустите, чтобы показывалось имя метода; а теперь просто нажмите на название метода, чтобы создать связь (рис. 8):

Обработка событий

Давайте впишем код в событие btnClickMe_Clicked, чтобы прочесть имя и фамилию и отобразить на экране сообщение в метке. Вот как выглядит этот код:

//HelloUniverseController.m
- (IBAction) btnClickMe_Clicked:(id)sender {
NSString *FirstName = txtFirstName.text;
NSString *LastName = txtLastName.text;
NSString *Message = nil;
if([FirstName length] == 0 && [LastName length] == 0)
Message = [[NSString alloc] initWithFormat:@"Anonymous says Hello Universe!!!"];
else if ([FirstName length] > 0 && [LastName length] ==0)
Message = [[NSString alloc] initWithFormat:@"%@ says Hello Universe", FirstName];
else if ([FirstName length] == 0 && [LastName length] == 0)
Message = [[NSString alloc] initWithFormat:@"%@ says Hello Universe", LastName];
else
Message = [[NSString alloc] initWithFormat:@"%@ %@ says Hello Universe", FirstName, LastName];
lblMessage.text = Message;
//Release the object
[Message release];
}

Метод делает пару простых вещей: он определяет имя и фамилию (Name и Last Name) и выясняет, какое сообщение в метке вывести на экран. Мы также создаем временную переменную под названием “Message“, чтобы удерживать сообщение, которое будет отображено в метке. Переменная размещена и инициализирована сообщениями alloc и initWithFormat соответственно. В конец переменная освобождена, потому что при работе с iPhone мы ответственны за очистку памяти. Самый простой способ запомнить, когда выпустить объект, – это когда вы создаете его, становитесь его владельцем и также ответственным за его освобождение.

Если вы нажмёте на Build and Go, вид будет невидим, потому как мы до сих пор его не добавили в окно. Давайте посмотрим, как мы сможем сделать это.

Добавления вида в окно

На этот раз мы не можем просто перетащить вид и добавить его в окно, таким образом, мы нуждаемся в другом способе добавления вида как подвида в окно. Мы уже знаем, что “HelloUniverseController” – это контроллер вида “HelloUniverse“, а “HelloUniverseAppDelegate” – это прикладной делегат, где окно сделано видимым в методе applicationDidFinishLaunching. В этом то методе мы добавим вид как подвид в окно. Прежде, чем мы сделаем это, прикладной делегат (HelloUniverseAppDelegate) должен знать о нашем контроллере вида. Добавьте следующие строки к файлу HelloUniverseAppDelegate.h, чтобы он выглядел следующим образом:

//HelloUniverseAppDelegate.h
@class HelloUniverseController;
@interface HelloUniverseAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
HelloUniverseController *hvController;
}
@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) HelloUniverseController *hvController;
@end

Из кода выше мы сначала добавили описание передового класса “HelloUniverseController“, потому что мы не хотим какой-либо круговой зависимости, когда будем импортировать заголовочный файл “HelloUniverseController” в HelloUniverseAppDelegate.m. Переменная и тип property HelloUniverseController также описаны. Property, как вы видите, написано с парой атрибутов, названных “retain” и “nonatomic“. Атрибут “retain” увеличивает количество ссылок переменного экземпляра на один, а атрибут “nonatomic” используется, потому что наша программа не многопоточная. Множество новичков-пользователей забывают синтезировать описанные property, поэтому, давайте сделаем это сейчас в самом верху файла HelloUniverseAppDelegate.m. Код выглядит так:

//HelloUniverseAppDelegate.m
@implementation HelloUniverseAppDelegate
@synthesize window, hvController;
...

Вид добавлен как подвид в окно метода applicationDidFinishLaunching, и вот как выглядит код:

//HelloUniverseAppDelegate.m
- (void)applicationDidFinishLaunching:(UIApplication *)application {
HelloUniverseController *hvc = [[HelloUniverseController alloc]
initWithNibName:@"HelloUniverse" bundle:[NSBundle mainBundle]];
self.hvController = hvc;
[hvc release];
[window addSubview:[self.hvController view]];
// Override point for customization after application launch
[window makeKeyAndVisible];
}

Вторая строка показывает, что мы импортировали заголовочный файл “HelloUniverseController“, а также синтезировали property hvController. В “былые” дни, чтобы создать property, мы должны были создать методы getter и setter, которые были бы чем-то вроде getHVController и setHVController. Синтезированное ключевое слово автоматически генерирует эти методы за нас. В методе applicationDidFinishLaunching мы распределяем и инициализируем временную переменную, назначаем её нашему property, освобождаем её, и вид, связаннй с контроллером вида, добавлен как подвид в окно. Ключевая вещь, которую необходимо запомнить заключается в том, что сообщение вида обращается к “hvController“, который возвращает вид, и добавляется как подвид в овно. Достоверный вид возвращается, потому что мы создали связь между видом переменного экземпляра и вида в nib файле. Наконец, property освобождается в методе dealloc, как показано ниже:

//HelloUniverseAppDelegate.m
- (void)dealloc {
[hvController release];
[window release];
[super dealloc];
}

Мы всегда распределяли и инициализировали переменные в одной одиночной линии, как показано ниже. Это, как правило, общепринятый способ. Но тот же самый код может быть написан различным способом:

HelloUniverseController *hvc = [HelloUniverseController alloc];
hvc = [hvc initWithNibName:@"HelloUniverse" bundle:[NSBundle mainBundle]];

Жмите Build и начинайте тестировать своё приложение.

Как спрятать клавиатуру

Ожидание в течение минуты после нажатия кнопки “Done” ни к чему не приводит. В идеале, мы бы хотели скрыть клавиатуру, когда уже нажата кнопка “Done“, независимо от того, какое текстовое поле мы в настоящее время редактируем. Чтобы скрыть клавиатуру, мы должны сделать две вещи: установить делегата для клавиатуры к File’s Owner и реализовать метод под названием textFieldShouldReturn в файле HelloUniverseController.m. Чтобы установить делегата, откройте Interface Builder двойным кликом на HelloUniverse.xib, выберите первое текстовое поле и нажмите на Tools -> Connections Inspector. Перетаскивайте мышью с пустой области рядом с делегатом под “Outlets” на File’s Owner. Назначьте делегата для следующего текстового поля тем же самым способом.

Метод textFieldShouldReturn вызывается, когда на кнопку “Done” кликали. И вот как выглядит код:

//HelloUniverseController.m
- (BOOL)textFieldShouldReturn:(UITextField *)theTextField {
[theTextField resignFirstResponder];
return YES;
}

Метод получает параметр с именем “sender”, который является объектом, вызывающим событие. Мы будем использовать тот же самый объект, к которому мы посылаем сообщение resignResponder, скрывающее клавиатуру в текстовом поле. Boolean переменная “Да” возвращается, чтобы сказать “sender”-у, что первый респондент прошёл.

Оригинал статьи: http://www.iphonesdkarticles.com/2008/07/first-iphone-application.html

Перевод: http://lookapp.ru/sdk/

Метки:

Если вам понравилась статья, подпишитесь на RSS!
  • Дима

    Спасибо. Мне статья помогла.

    • http://intensedebate.com/people/Nitr0geN Nitr0geN

      Я очень рад, значит не зря все это :)

  • Lookapp

    Уважаемые админы этого замечательного сайта. Укажите в строке «Перевод:» активную ссылку на сайт — http://lookapp.ru/sdk/

    Соблюдайте правила этикета пожалуйста, когда используете чужой материал. Спасибо.

    • http://devmac.ru Игорь

      Исправлено!

  • Lookapp

    Спасибо. :)

  • Novice

    Удивительно корявый перевод. Но и на том спасибо.

  • Andrew

    Никак не пойму, что за кнопка «Done»? у нас-то на клавиатуре такой кнопки нету, да и IBAction и внутри viewCOntroller кнопку не создавали. Можно этот момент по поводу прятяния клавиатуры помедленней… Трижди благодарен.

    • http://devmac.ru Игорь

      Имеется ввиду кнопка, при нажатии на которую скрывается клавиатура и в поле остается введенный текст. В русской клавиатуре она вроде бы называется «Готово».

      • Andrew

        Но в Моем симуляторе нет на выезжающей клаиватуре таких кнопок. Хотя Уже, сокрытия клавы добился помещением [theTextField resignFirstResponder]; внуть кнопки IBAction метода

        • http://devmac.ru Игорь

          Я рад, что все у Вас получилось.

        • http://devmac.ru Игорь

          Да действительно нету. Я посмотрел внимательнее. Думаю что это кнопка btnClickMe.

      • Andrew

        Да и клава-то на симуляторе английская…. (xcode 3.2.3 )

  • Ирина

    У меня почему-то окно Interface Builder не открываеться при двойном щелчке “MainWindow.xib” . В чем может быть дело? Heeelp!!!

    • Anton

      Все просто — у вас ненастроен запуск редактора Interface Builder для работы с xib файлами.

      Щелкните по файлу правой кнопкой -> Preferences -> Open General Preferences -> File Types -> File -> xib и выберите External editor (Currently Interface Builder)

      У меня после этого заработало.