Прикладной код выполняется только потому, что среда Cocoa посылает ему событие и в нем установлен метод, готовый принять событие.

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

Данное обстоятельство представляет одно из самых главных затруднений для программирующих для операционной системы iOS. Недостаточно знать, как написать прикладной код, но нужно уметь правильно разделить на части и распределить его, учитывая те моменты, когда среда Cocoa предполагает обратиться к нему. Прежде чем вы напишете хотя бы одну строку прикладного кода, для вас уже будет составлена в основном каркасная структура класса, чтобы подготовить его к приему событий, которые собирается посылать ему среда Cocoa.

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

initWithCoder: или initWithNibName:bundle:1

Это методы времени действия контроллера типа UlViewController, где выполняется специальная инициализация экземпляра.

viewDidLoad

Это метод времени действия контроллера типа UlViewController, где выполняется инициализация, связанная с представлением.

viеwDidAppeaг:

Это метод времени действия контроллера трпа UlViewController, где устанавливаются состояния, требующиеся только при отображении представления на экране. Так, если нужно зарегистрироваться для получения уведомлений или установить таймер, то все это, скорее всего, придется сделать именно в данном методе.

vi ewDidDisappear:

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

supportedlnterfaceOrientations

Это метод запроса контроллера типа UlViewController, где указываются допустимые ориентации мобильного устройства для основного представления данного контроллера.

 

numberOfSect ionsInTableView:

tableView:numberOfRowsInSection:

tableView:cellForRowAtlndexPath:

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

 

tableView:didSelectRowAtlndexPath:

Это метод действия пользовательского делегата класса UITableView, где организуется реагирование на касание строки таблицы.

dealloc

Это метод времени действия объекта типа NSObject, где выполняется очистка этого объекта из памяти по окончании срока действия объекта.

Допустим также, что метод viewDidAppear: был вызван для регистрации на получение конкретного уведомления и установку таймера. В таком случае у данного уведомления и таймера имеется свой селектор, если только не используется блок, а следовательно, придется реализовать методы, описываемые этими селекторами.

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

Такую логику построения прикладной программы совсем не просто понять! Не сочтите это за критику в адрес среды Cocoa, поскольку трудно себе представить иной принцип ее действия. Если быть объективным, то следует сказать, что прикладную программу, написанную в среде Cocoa, даже если разработать ее самостоятельно, очень трудно читать, поскольку она состоит из многочисленных несвязанных точек входа, каждая из которых имеет свое смысловое назначение и вызывается в свой заданный момент, который не совсем очевиден из ее анализа.

Для того чтобы понять назначение и функции гипотетического класса, нужно уже знать, например, когда вызывается метод viewDidAppear: и каким образом он обычно используется. В противном случае очень трудно доискаться логики и поведения прикладной программы, не говоря уже о том, как интерпретировать даже то, что уже в ней обнаружено. Эти трудности значительно возрастают при попытке прочитать чужой прикладной код (это одна из тех причин, по которым примеры кода оказываются не всегда полезными для начинающих, как пояснялось в главе 8).

Глядя на код прикладной программы для операционной системы iOS (даже своей собственной), можно легко прийти в недоумение от одного только вида всех тех методов, которые автоматически вызываются из среды Cocoa при разных обстоятельствах. По мере накопления опыта вы, конечно, научитесь быстро распознавать в коде такие элементы, как замещаемые методы из класса UlViewController, делегат табличного представления и методы источника данных. С другой стороны, никакой опыт не подскажет вам, что определенный метод вызывается в виде действия кнопки или по уведомлению. Здесь немалую помощь оказывают комментарии, поэтому настоятельно рекомендуется снабжать (обильно если, требуется) комментариями каждый метод в приложении, разрабатываемом для операционной системы iOS, указывая назначение метода и при каких обстоятельствах он должен вызываться, особенно если это точка входа, в которой он вызывается из самой среды Cocoa.

При написании приложений в среде Cocoa самыми распространенными оказываются не программные ошибки в коде, а размещение кода не в том месте. Нередко прикладной код не выполняется вообще, не вовремя или не в том порядке следования его фрагментов. Подобные жалобы можно нередко можно встретить на форумах пользователей среды Cocoa в Интернете. Ниже приведены характерные тому примеры, взятые из одного из таких форумов, где они появились в течение буквально двух дней.

  • "Возникает задержка между моментом появления моего представления и моментом появления нужной надписи на кнопке”. Это объясняется тем, что прикладной код, устанавливающий надпись на кнопке, размещается в методе viewDidAppear:, а это слишком поздно. Выполнение этого кода должно начаться раньше, возможно, в методе viewWillAppear:.
  • "Мои дочерние представления располагаются программно в коде, но в конечном итоге все они действуют неверно”. Это объясняется тем, что прикладной код размещает дочерние представления в методе viewDidLoad, а это слишком рано. Выполнение этого кода должно начаться позже, когда уже определены размеры представления.
  • "Мое представление все равно поворачивается, даже если метод supported InterfaceOrientations моего контроллера представления не разрешает это делать”. Дело в том, что метод supportedlnterfaceOrientations реализован не в том классе. Его нужно реализовать в классе UINavigationController, содержащем контроллер представления.
  • "Я устанавливаю связь с действием для события Value Changed, наступающего в текстовом поле, но мой код не вызывается, когда пользователь редактирует данные в этом поле”. Дело в том, что связь была установлена не с тем действием. Ведь текстовое поле инициирует событие Editing Changed, а не Value Changed.

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

Кроме того, в среде Cocoa возможна программная ошибка, в результате которой события вызываются совсем не так, как описано в документации. Поскольку исходный код среды Cocoa закрыт для доступа, то выяснить скрытые подробности ошибки вряд ли удастся. Поэтому при разработке приложения рекомендуется обильно снабдить его код средствами простейшей самодиагностики, воспользовавшись функцией NSLog () (см. главу 9). Тестируя код, внимательно следите за выводом на консоль и проверяйте логичность выводимых сообщений. Вы будете удивлены тем, что обнаружите.

Например, во время разработки одного из своих приложений я неожиданно обнаружил, что в подклассе, производном от класса UlViewController, метод viewDidLoad вызывался дважды во время запуска приложения на выполнение, а этого не должно было быть. Правда, код моего приложения был обильно снабжен вызовами функции NSLog (), иначе я так бы и не выявил ошибку. Введя дополнительные вызовы функции NSLog () в свой код, я обнаружил, что метод viewDidLoad вызывался в тот момент, когда еще не завершилось выполнение метода awakeFromNib, чего на самом деле не должно было быть. Причиной тому стала моя ошибка: я обращался к свойству view контроллера представления во время выполнения метода awakeFromNib, что и приводило к вызову метода viewDidLoad. Как только я исправил свою ошибку, упомянутая выше проблема исчезла.


 

 

 

Добавить комментарий