Pull to refresh

История разработки iOS-приложения. В основном про грабли

Development for iOS *Objective C *
Sandbox
Я понимаю, что на Хабре таких историй уже очень много. Но каждая история уникальна и является маленькой каплей в чаше чьего-либо вдохновения. В этой статье я расскажу, как писал свое приложение для iOS, на какие грабли наступил и что бы я сделал по-другому в своих будущих проектах.

Идея


Основа основ — это идея. Сложно что-либо реализовать без четкой идеи, что должно быть в конце. И такая идея у меня была. Мне всегда были интересны количественные показатели моей жизни. Причем именно тех критериев, которые технике померить просто невозможно. Они субъективны и оцениваются нами по ощущениям. Родилась идея сделать приложение, которое позволило бы оценивать прошедшей день именно по таким субъективным идеям. К тому же, было бы неплохо, если бы оно еще и помогало отмечать прогресс на пути к достижению цели.

Описание идеи


Идея сама по себе — это, конечно, очень хорошо. Но она ничто, пока не обретет материальное воплощение. И первый шаг на этом пути — её описание. Составление первых описаний будущего приложение, наброски первого ТЗ, первые наброски интерфейса. Вот тут я совершил самою большую ошибку. Про нее написано в каждой подобной статье, и все равно все ее совершают. Казалось бы, всё приложение у меня в голове, я могу представить каждый экран, каждое действие, но, как выяснилось позже, этого мало. В процессе работы появляется много нюансов, мелочей, которые в голове почему-то не просматривались и вот как раз они-то и отнимают львиную долю времени на разработку. К своему следующему проекту я подошел более основательно и ТЗ на него включает описание переходов, реакций на нажатие, анимаций и т.д. Одним словом, необходимо устранить по возможности все белые пятна в идее. Предусмотреть максимальное количество сценариев использования. Это значительно ускорит работу на следующих этапах разработки.

Разработка


Не следует думать, что вы можете все. К сожалению, это не так. Я решил и поплатился за это потраченными временем и нервами. Мне казалось, что поскольку я представляю себе конечный продукт, то и рисовать мне его не надо, а сделаю я все по ходу программирования. Отличное заблуждение. В итоге получил ужасный не только UI, но и UX. Хотя работающий прототип создал.



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


Разработка. Перезагрузка


Первый вариант никуда не годился и, более того, у меня была полная уверенность в том, что Apple не должны пускать его в AppStore. Поэтому было решено перезапустить разработку. Первое, что я сделал — это переписал ТЗ. Оно уже не было просто описанием идеи, хотя и до идеала ему было еще далеко. В нем появились описание экранов приложения, переходов между ними.

Я нашел дизайнера для приложение. Про поиски дизайнеров, да и работников, написано достаточно много. Я искал через freelansim.ru, ну и, конечно, со всеми переговорил. Надо отметить, что выбор людей для работы — это всегда субъективное и неподдающееся логическому объяснению решение. Мне даже кажется, что это сродни лотереи.

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

Дизайн создавался и потихоньку приложение обретало внешний вид. Тем временем, я решил, что раз уж перезагружать разработку, то делать все максимально по уму. Поскольку из собственного опыта у меня был только один неудачный прототип, я принялся за изучение чужого опыта. Вот что я вынес из прочитанных статей и просмотренных докладов:
  • Используйте CocoaPods — отличный и простой инструмент, помогающий управлять сторонними библиотеками;
  • Структурируйте проект в xCode — я разбил свой проект довольно примитивно, но, в тоже время, довольно понятно.



  • Задумайтесь о статистике еще до начала разработки. Для статистики я использовал проект Yandex.Metrika и Parse. Правда, статистика Parse пошла приятным дополнением. В основном я подключал этот сервис для Push Notification, но теперь планирую использовать его как backend для данных пользователей. Я выписал отдельно все события, которые хочу отслеживать в приложении, и уже по ходу разработки просто добавлял их, не тратя время на решение;
  • Вынесите все, что встречается в проекте более, чем в одном классе, в отдельный файл, которым будет легко управлять и изменять. Сюда попадают различные перечисления, дефайны, константы и прочие данные.

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

Недочеты, откровенные просчеты в организации проекта и интересные ошибки


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

Локализация приложения


На WWDC14 Apple представила новый способ локализации приложений. Можно экспортировать весь проект в .xliff файл и переводить его. Это практически стандарт в мире переводчиков. По крайней мере, на презентации сказали именно так. Я обрадовался: хороший, легкий способ, и все в одном месте. В том месте программы, где нужен будет перевод, вместо обычной строки пишется макрос:
NSLocalizedString(@“string”, @“comment”).
В начале та строка, что требует перевода, а затем комментарий, в основном, для переводчика. На программу он никак не влияет. Но вот беда, от ошибок никто не застрахован, да и есть места, которые повторяются в программе. В общем, если вы где-то ошиблись, то для исправления придется просмотреть весь проект. Но и это еще не все. Дело в том, что строка для перевода в .xliff файле станет ключем, и если вы ее поменяете в программе, а переводчик не изменит файл перевода, то вы получите две строки с одинаковым переводом и разными ключами. Xcode не найдет перевод и место останется не локализованным.

Решением этой проблемы стало комбинирование старого и нового способа локализации. Все строки, необходимые для перевода, выносятся в файл Localizable.strings в виде ключ-значение. И обращаемся уже к ключу. Теперь мы получаем возможность исправлять исходные тексты, не опасаясь за перевод. А переводчик, опять же, получает знакомый и удобный формат для работы.

Странные ошибки


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

typedef enum: NSInteger{
    EDEvaluatePriceHundredPoint,
    EDEvaluatePriceTenPoint,
    EDEvaluatePriceThreePoint
}EDEvaluatePrice;

Сами значения хранятся в CoreData и представлены в виде NSNumber. При выборе я решил делать следующие сравнения:

if (c.priceCriterion == [NSNumber numberWithInteger:EDEvaluatePriceHundredPoint]) {
}

Мне казалось это логичным, тем более это работало у меня на телефоне. Хотя тут сравниваются два разных объекта.
А вот на iPhone 5S и новее это уже не работало и появлялись пустые ячейки. Странная история, которую я до сих пор не понимаю. Но решается просто:

if ([c.priceCriterion integerValue] == EDEvaluatePriceHundredPoint) {
}

Вторая ошибка проявлялась только на iPhone 6 Plus и заключалась она в сломанной верстке приложения. К тому же не на всех его экранах, а только на избранных. Проблема оказалась в представленных в xcode 6 constraint to margin. Причем по умолчанию эта функция включена. Опять же не могу сказать, почему именно такое происходило, мне кажется, что проблема в использовании Containers. Но ведь этот же механизм использован Apple, например, в TabBarController. Да и проблема, опять же, проявлялась не всегда.

P.S. Несмотря на все странности и кучу подводных камней, мне все же понравилось разрабатывать для iPhone. Мое приложение находится в сторе всего пару недель, поэтому говорить о каких бы то ни было результатах еще рано. Позже я опубликую отчет о продвижении приложения.
Tags: iOSobjective-cApple
Hubs: Development for iOS Objective C
Total votes 12: ↑7 and ↓5 +2
Comments 8
Comments Comments 8

Popular right now