Как найти вызовы «свежих» API, которые ломают ваше приложение на старых SDK

Итак, как же найти вызовы «свежих» API, которые ломают ваше приложение на старых SDK. На самом деле я знаю только один из ответов на этот вопрос. Надеюсь, кто-то из читателей блога расскажет мне еще один или два. Сегодня утром пришло письмо от одного из заказчиков, что я обещал им безоблачную работу приложения на iOS SDK не ниже версии 5.0. На самом деле они использовали всегда версию 6.0 и выше. Это приложение ддля внутренних нужд внутри компании, и оно не размещается в AppStore. Но вдруг им потребовалось запустить приложение на iPod 3Gen с iOS 5.1.1 на борту … и бабах! Все упало. Они сразу же связались со мной, и прислали несимволизованный crashlog. На самом деле даже из такого лога было видно в чем проблема. Я использовал метод dequeueReusableCellWithIdentifier: forIndexPath:, введенный только в 6-ой версии, вместо хотя бы этого метода dequeueReusableCellWithIdentifier:

Можно было бы все быстро поправить и отослать, но где гарантия, что дальше не будет проблем, а симулятора 5.1.1 или устройства, чтобы проверить у меня нет. Тогда я начал лазить по stackoverflow с целью найти какое-то решение, которое мне поможет выловить все мои «проколы». Оказалось, что подобной встроенной функциональности в XCode 5 не существует. Надо сказать, что хотя я шапочно знаком с разработкой под Android, я знаю, что там такая функциональность сразу включена в их analyzer. Вот этот ответ на stackoverflow меня заинтересовал — http://stackoverflow.com/questions/19111934/get-xcode-5-to-warn-about-new-api-calls . Но к сожалению, как я не пробовал, мне не удалось получить никаких warnings компилятора. Если кто-то знает, как заставить работать эту штуку с макросами, буду рад услышать. Тут я заметил, что есть какой-то платный софт для этого дела, и перешел на сайт — http://www.deploymateapp.com и после недолго игры с демкой, купил программу. Относительно этого моего проекта, трата 20 баксов оказалась напрасной, так как больше серьезных проблем с совместимостью между версиями не осталось кроме использования параметров NSLineBreakByWordWrapping (6.0) вместо UILineBreakModeWordWrap (5.0), но так как числовые значения этих констант не поменялись, то я не стал ничего менять. Но о покупке я совершенно не пожалел, так как мне понравилось, что я практически мгновенно получил информацию по моему проекту, и быстро ответил заказчику. А это, порой, самое главное.

Podrunner — музыка для бега

Где-то 4 месяца назад я начал бегать. Купил кроссовки и в лес! Но, так как я начинающий бегун, мне надо было соблюдать определенный ритм первое время — бежать очень очень медленно: примерно 8 минут километр. Когда я читал о беге, то мне попадались статьи, где рассказывало, что существуют готовые сборники музыки для бега с определенным ритмом BPM. Так я нашел сайт — http://www.djsteveboy.com/podrunner.html.  Скачал несколько треков (совершенно бесплатно), основываясь на различных калькуляторах в сети, как пересчитать BPM в км/час или мин/км. Оказалось, что для меня это не подходит, и опытным путем выбрал себе 142 BPM для начала, да и мелодия первого трека понравилась. Но еще больше понравился другой трек — 155 BPM, и я еще тогда подумал, что было бы классно, если бы его играть медленнее.

В итоге я купил себе приложение Podrunner. Вернее скачал бесплатно с AppStore, а затем купил за $1.99 встроенную покупку. Купил ее скорее от желания поддержать хорошее начинание человека. Но за эти деньги я также получил удаление рекламы из приложения, пропуск речевого приветствия в каждом музыкальном файле, а также возможность изменять скорость проигрывания  любого из треков в программе. То есть, я наконец мог послушать любимый трек 155 BPM хоть быстрее, хоть медленнее, просто изменяя BPM в приложении.

Кстати, я слышал, что серьезные бегуны предпочитают бегать при очень высоких каденциях (ритме) 170-180, потому что это оптимальный ритм для мышц. Так вот это приложение позволит вам легко держаться в заданном ритме, даже если бывалый бегун.

Когда скачивал, то боялся, что на iOS7 что-то будет работать не так, так как приложение уже с историей, и последний раз обновлялось давно. Но оказалось, что все прекрасно работает.

Еще раз спасибо DJ Steve «boy» и разработчикам!

Мелочь, а приятно!

Вот за что я люблю Apple — за такие «мелочи». Допустим, я хочу сделать UILabel, который должен показывать время. А время я пишу стандартно — через двоеточие «01:15». Вы уже можете видеть в этой записи, что браузер показывает обычное двоеточие. Точно также было и до выхода iOS7, посмотрите на картинку ниже. Двоеточие смещено вниз относительно цифр и имеет квадратную форму точек для данного шрифта.

Снимок экрана 2013-09-24 в 11.11.03

Но с выходом iOS7 и TextKit мы можем делать разные трюки с текстом, с некоторыми ограничениями.

#import <CoreText/CoreText.h>

UIFont *font = [UIFont systemFontOfSize:120.0];

NSArray *timeFeatureSettings = @[
 @{UIFontFeatureTypeIdentifierKey:@(kCharacterAlternativesType),
 UIFontFeatureSelectorIdentifierKey:@(1)}
 ];

UIFontDescriptor *original = [font fontDescriptor];
 UIFontDescriptor *timeDesc = [original fontDescriptorByAddingAttributes:
 @{UIFontDescriptorFeatureSettingsAttribute:timeFeatureSettings}];
 UIFont *timeFont = [UIFont fontWithDescriptor:timeDesc size:0.0];

Теперь, используя шрифт, полученный в последней строчке снова рисуем UILabel и видим совсем другую картину. У нас получились настоящие часы. Мелочь, а приятно! И мне приятно и пользователям!

Снимок экрана 2013-09-24 в 11.10.12

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

а если мы добавим еще атрибутов в шрифт, например, сделаем, чтобы тоненькая цифра 1 не занимала так много места, то сделаем картинку еще лучше.

NSArray *timeFeatureSettings = @[
  @{UIFontFeatureTypeIdentifierKey:@(kCharacterAlternativesType),
    UIFontFeatureSelectorIdentifierKey:@(1)
  },
  @{UIFontFeatureTypeIdentifierKey:@(kNumberSpacingType),
  UIFontFeatureSelectorIdentifierKey:@(kProportionalNumbersSelector)
  }
];

Снимок экрана 2013-09-30 в 10.11.12

Более подробно со всеми новшествами разработчики могут ознакомиться в видео с WWDC 2013 — Using Fonts With Text Kit

Война Вирусов — мой первый публичный проект на Github

В начале 2010-го года я еще только учился разработке под iOS, которая даже еще так не называлась. Первая программа еще в декабре 2009 была «Крестики и нолики». Тема рекурсии меня увлекла, и как-то плавно перетекла в разработку игры «Война вирусов». В Википедии про нее есть статья, правда ее почему-то хотят удалить. Надо будет ее себе сохранить для будущего. Не помню точно, почему я выбрал эту игру, скорее всего потому, что ниша была свободна, а тема была мне интересна. Надо было на чем-то учиться. Это сейчас я понимаю, что это не лучший вариант для обучения, да и с точки зрения потом программы в AppStore это почти дохлый номер — народ такие программы не любит, у них есть очень узкий круг энтузиастов, интересующихся логическими играми.

Решил выложить этот проект на github.com как публичный (лицензия MIT). Игра полностью играбельная на сегодняшний день, правда буквально вчера обнаружил, что не доделал фиксацию выигрыша или проигрыша — надо будет доделать в ближайшее время. Видимо потому, что программа сегодня думает очень и очень долго, что для мобильного устройства практически неприемлемо, и я никогда не доходил до конца. Даже на симулятора айфона компьютер делает ход примерно 3-5 минут, при этом сейчас компьютер смотрит всего на два хода вперед. Ограничить время «думания» можно константой в коде. Но если поставить слишком маленькую цифру, то он будет играть очень тупо, так как пока никакого ранжирования важности ходов пока нет, как в шахматных программах, когда сначала исследуются все ходы со взятиями, а затем другие. Одна из основных проблем, по крайней мере для меня была и есть — что один ход это три клеточки. Если в шахматах один ход это один ход, то у меня их три и надо создать все сочетания ходов по три клетки. Причем, если мы пронумеруем клетки от 1 до 100, то по идее ход 17, 42, 55 это точно такой же ход как 55, 42, 17 — но система генерации ходов сгенерирует их сначала как разные, и нам нужно будет их удалять. Удалять дубликаты надо обязательно, так как запуская их в рекурсию, мы тратим больше времени, чем на их отсеивание. Кстати про отсеивание дубликатов из массива NSMutableArray мы как раз и поговорим в следующий раз.

Так что, кому интересны разработка логических игр — милости просим в наш репозиторий 🙂

https://github.com/soj/iVirusWar

А вы хотите купить билеты на WWDC?

Как известно, билеты на WWDC раскупаются чуть ли не за час. Все стремятся попасть на эту конференцию. Поэтому разработчики придумывают всяческие уловки, чтобы не пропустить минуту начала продажи билетов. Один из разработчиков выложил на github проект, который каждый 2 минуты даже в бэкграунде проверяет не изменился ли внешний вид страницы продажи билетов. Если изменился, то сообщает об этом. По слухам, уже было несколько фальшивых срабатываний, когда Apple чуть-чуть меняла скрипты на сайте. Так что, если вы тот, кто хочет не пропустить билеты на WWDC — это ваш выбор.

https://github.com/rmatta/WWDCAlertApp

Пара новых правил с 1 мая в iTunesConnect

Starting May 1, new apps and app updates submitted to the App Store must:

  • Be built for iOS devices with Retina display, and iPhone apps must also support the 4-inch display on iPhone 5. Learn about preparing your apps by reviewing the iOS Human Interface Guidelines.
  • Not access UDIDs. Please update your apps and servers to associate users with the Vendor or Advertising identifiers introduced in iOS 6. You can find more details in the UIDevice Class Reference.

Core Data и mogenerator

Давно я хотел написать этот пост, но все руки не доходили. А все потому, что хотел все подробно рассказать со скринами, тестовыми проектами и прочими радостями. Потом решил сделать этот анти-пост, в котором не будет ни одного скрина и ни строчки кода.

Я очень люблю фреймворк Core Data.  Он мне нравится своей простотой и красотой одновременно. Там безусловно есть свои тонкости, но в целом штука очень удобная, и не зря Apple старается нам ее подсунуть почти в каждый ваш проект с данными. Так как я уже делал несколько проектов с использованием Core Data, то стараюсь периодически посматривать что-то интересное на эту тему. И чуть ли не полтора года назад я напал на mogenerator. Что же это такое? Это скрипт, который на основе вашей модели данных в проекте генерирует код классов сущностей. Но ведь мы можете делать все тоже самое сами в Xcode? Конечно да, но этот скрипт генерирует не один, а два класса на каждую сущность (entity). Один класс генерируется для поддержки вашей модели данных, и его может править только сам скрипт — вы туда не лезете. А второй класс, являющийся подклассом предыдущего, как раз служит для нас разработчиков, где мы вольны описывать любые манипуляции с этим NSManagedObject. Настроив вашу систему на работу с этим скриптом в проекте, вы забываете о перегенерации класса вашей entity — скрипт делает это за вас, и одновременно с этим скрипт не переписывает ваш «человеческий» файл, в котором у вас расписано кастомное поведение объекта. Причем удобно сделать в проекте новый aggregate target, в него вписать выполнение скрипта, а ваш основной тарджет поставить в зависимость. Благодаря этому какие бы изменения вы не вносили в свою модель данных, кроме добавления новых entity — вы автоматически получаете рабочий проект (при прочих равных условиях). В случае добавления новой сущности, вам надо будет добавить эти файлы к проекту, как впрочем и без использования mogenerator.

Основные три ссылки на эту тему вот:

https://github.com/rentzsch/mogenerator

http://rentzsch.github.com/mogenerator/

http://raptureinvenice.com/getting-started-with-mogenerator/

Кому будет интересно, разберется сам — там все супер просто. Если же все-таки будут вопросы, то пишите, и я расскажу подробнее.

Для меня плюсы очевидны — я получаю гораздо лучше читаемый и управляемый код. Остальные несколько плюсов в третьей ссылке.