12 недель. Неделя 1. FancyTwitter

Итак, вот и настал день первого приложения в разделе «12 недель программирования и дизайна». Как я уже писал ранее  что для первого раза я выбрал Александра Зайцева с его дизайном приложения для Твиттера. Мне понравился сам дизайн, а большим плюсом стало наличие PSD файла к нему. В дальнейшем придется, видимо, всегда выбирать интересные проекты на dribbble.com только c PSD. Наше микро-приложения я назвал FancyTwitter.

Когда мы открываем файл, то сразу видим, с чем нам придется поработать. А именно:

  • кастомный цвет UINavigationBar
  • две кнопочки UIBarButtonItem на нем
  • необычный кастомный элемент с текстом Favorites
  • кастомная клеточка UITableViewCell для таблицы
  • ну и красивый задник под этой табличкой

В принципе, ничего сложного. При разборе файла, я обнаружил, что слой, который прорисовывает navigation bar, состоит просто из белого слоя с 10% прозрачностью. Если я нарисую точь в точь такой в программе, то текст, который будет съезжать вверх при скроле, начнет накладываться на кнопки и заголовок, и это будет некрасиво и нечитаемо. Поэтому я обратился к автору с вопросом, что же он имел в виду. Это следует делать всегда, если вам что-то не понятно. Спрашивать заказчика или дизайнера. Чаще всего, все удается дизайнеру разложить по слоям, и мне как разработчику ничего не надо сливать в Photoshop. Но в данном случае, файл готовился для себя, поэтому совершенно нормально, что автор мне ответил, что он предполагал непрозрачный navigation bar и предложил мне просто самому растрировать этот слой и получить нужный мне png. Кстати, я всегда стараюсь сам резать присылаемые PSD, потому что дизайнер не всегда представляет как я работаю, или мой стиль нарезки, поэтому проще оказывается все резать самому. Также Александр объяснил мне, что наш красивый разблюренный задник статичен по его задумке, но предполагается еще несколько задников, которые пользователь может менять по своему желанию. Этому мы уделим особое внимание дальше.

Снимок экрана 2014-06-20 в 16.22.01

Так как мы будем только симулировать работу Твиттер-клиента, то перво-наперво я создал простой класс FTDataSource, который у нас отвечает за выдачу нам твиттов. Он организован крайне примитивно — это просто массив, содержащий NSDictionary, в которых содержаться все нужные нам данные — имя пользователя, имя его твиттера, картинка профиля, текст и картинка, которую разместил пользователь. Это очень большое упрощение, но на него на приходится идти. Мы можем впоследствии заменить код в этом классе и получать реальные твиты, но пока оставим все как есть. Наша задача просто «натянуть» этот дизайн на код.

Снимок экрана 2014-06-20 в 16.28.39

Далее в первых строках нашего приложения вы видите некий класс ThemeManager. Он служит именно для того, чтобы быстро менять внешний вид всего приложения. Этот паттерн был показан помоему на WWDC 2012, и если кому-то будет интересно, я скажу название сессии. А также к ней есть исходный код. Хотя Apple и не приветствует всякого рода skins в своих приложениях, тем не менее иногда это бывает полезно. Apple в своем гайде по стилю пишет, что всегда старайтесь делать так, чтобы удовлетворить максиально широкую аудиторию всего одной настройкой, а не делать десяток,в которых пользователь утонет. Для чего этот ThemeManager может быть полезен?  Например, вы разрабатываете приложение, и еще не решили на какой варианте остановиться. Вы делаете два-три варианта и показываете их людям. С помощью этого метода вы можете делать разные соборки только меняя один из параметров в свойствах проекта.

Как это работает? Мы делаем singleton класс — ThemeManager который соответствует нашему же протоколу Theme. В этом протоколе мы указываем все-все-все параметры, которые мы планируем менять. В нашем случае это цвета текста, изображение задника, изображение navbar-a. Когда приложение стартует, то инициализирует один из классов, которые и реализуют наш протокол Theme. Также у менеджера есть общая часть, в которой можно прописать, например, все связанное с UIAppearance. Там же есть пример, как можно кастомизировать таблицу.

#import <UIKit/UIKit.h>

@protocol Theme <NSObject>

- (UIColor *)profileNameColor;
- (UIColor *)twitterNameColor;
- (UIColor *)tweetColor;
- (UIImage *)navigationBackgroundForBarMetrics:(UIBarMetrics)metrics;
- (UIImage *)backgroundImage;

@end

@interface ThemeManager : NSObject

+ (id <Theme>)sharedTheme;

+ (void)customizeAppAppearance;
+ (void)customizeTableView:(UITableView *)tableView;

@end

Едем дальше. В Photoshop я нарезал задник в двух разрешениях — для ретины и не для ретины. Задники получились просто огромных размеров. То есть два задника в сумме порядка 3,5 мегабайт. А потом я сделал еще и зеленый вариант для демонстрации. В результате наше приложение еще ничего не умеет, а уже весит не слабо. Если кто-то, кто меня читает знает, что с этим можно сделать — то милости просим в комментарии. Мое же мнение пока такое, что все переливающиеся вещи очень красивые, но с точки зрения пользователя, они очень затратны. Программист тоже мучается, пытаясь все это реализовать. Самым приемлемым вариантом мне кажется использовать некий паттерн рисунка, а затем делать из него заливку (что-то типа обоев, которые мы все любим клеить на стены). Вообщем, это место оставило у меня чувство некой неудовлетворенности.

В Storyboard я создал ViewController, который содержит UIImageView задника, а на нем прозрачная таблица с прозрачными клеточками. Там же сразу в Storyboard я создал макет нашей клеточки, содержащий все те же 5 элементов, что и наши данные. Я использовал AutoLayout для этой клеточки. Это помогло мне не рассчитывать два раза высоту блока с текстом твитта. Один раз я обязан это сделать при расчете высоты клетки в методе heightForRowAtIndexPath. После того, как я задал высоту, AutoLayout автоматически растягивает многострочный UILabel в моей клеточке.

Снимок экрана 2014-06-20 в 16.35.12

Я создал подкласс UITableViewCell, куда передаю NSDictionary, содержащий наши данные по одной клеточке. Далее я разбираю их по местам. В данном примере мне пришлось работать с методом objectForKey. В обычной практике, я стараюсь свести к минимум такой код. Так как компилятор не может проверить ни правописание вашего key, ни тип данных, который метод возвращает. Поэтому потенциально это очень неприятно. Куда удобнее было бы, если бы мы получали, например, объект Tweet унаследованный от  NSManagedObject, а в нем были бы нужные нам properties. Но для симуляции пока пойдет и так.

Хотелось бы отметить, что в коде клеточки мы обращаемся к нашему ThemeManager, чтобы получить цвет текста. Для скругления изображений мы пользуемся старым добрым setCornerRadius:20.0 но, начиная с iOS 7.1 мы обязаны также принудительно указывать clipsToBounds = YES для данного view. Также вы можете заметить, что у нас есть специальный метод, который находит в тексте гиперссылку, и согласно дизайна отрезает у нее «http://« часть, а также окрашивает ссылку в особый цвет. Также немного пришлось повозиться с межстрочным расстоянием. Оно регулируется с помощью добавления экземпляра NSMutableParagraphStyle к нашей attributed string. Обратите внимание, что ищем вхождение гиперссылки мы с помощью Apple-овского класса NSDataDetector. Рисовать свой сеператор между клеточками я не стал, а просто отодвинул его inset в InterfaceBuilder, чтобы он соответствовал дизайну.

-(NSAttributedString*)getAttributedTweet:(NSString*)tweet
{
    NSError *error = NULL;
    NSDataDetector *detector =
      [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink error:&error];

    NSArray *matches = [detector matchesInString:tweet
                                         options:0
                                           range:NSMakeRange(0, )];

    NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithString:tweet];

    for (NSTextCheckingResult *match in matches) {

        NSString *stringWithoutHttp = [[[match URL] absoluteString]
                                       stringByReplacingOccurrencesOfString:@"http://" withString:@""];
        [string replaceCharactersInRange:[match range] withString:stringWithoutHttp];
        NSRange oldRange = [match range];
        NSRange newRange = NSMakeRange(oldRange.location, oldRange.length-7);
        [string addAttribute:NSForegroundColorAttributeName
                       value:[UIColor colorWithRed:253.0/255.0 green:166.0/255.0 blue:118.0/255.0 alpha:1.0]
                       range:newRange];

    }

    [string addAttribute:NSParagraphStyleAttributeName value:paragrahStyle range:NSMakeRange(0, [string length])];

    return string;
}

Дальше я нарезал две кнопочки, которые на navigation bar. Дизайнер совершенно правильно сделал из размером 20×20 points. Но вот только, если мы создадим на их основе кнопки, то увидим, что они смещены чуть-чуть больше к центру, чем в нашем дизайне. У нас они гораздо ближе к краю экрана. Я оставил их как есть, потому что мне этот вариант показался более правильным. Я стараюсь всегда говорить дизайнер или заказчику, что это мне кажется более правильным. Если мы нарезали нужную картинку правильного размера, сделали кнопку по умолчанию, и поставили ее на панель, а она стоит не там, то может ее правильный вариант именно этот? Заказчик всегда барин, и он может сказать, а я хочу все-таки ближе к краю экрана. И тогда мы берем один из методов, и двигаем кнопку вбок, но зато мы высказали свои замечания, что кнопка слишком близко к краю, и это может быть не удобно пользователю. Ниже мы видим наложение двух изображений в фотошопе. Так я обычно проверяю, что соответствую дизайну.

Снимок экрана 2014-06-20 в 16.39.16

Что касается Favorites со стрелочкой вниз, то такого элемента у Apple не существует, и такой навигации тоже. Но заказчик хочет именно так. Тем более, что некоторые распространенные приложения используют это — например, ВКонтакте. При нажатии на кнопочку-заголовок, у нас выезжает таблица с вариантами, мы выбираем какой-то, таблица уезжает обратно, а мы обновляем таблицы с новыми данными, а также меняем текст в этой кнопке-заголовке. Это все сделано у меня с помощью двух классов NavBarTitleView и SectionsTableViewController.

NavBarTitleView создает view, на котором расположен текст текущего раздела и изображение стрелочки вниз. К этому вью прикручен UITapGestureRecognizer, благодаря которому, мы знаем, когда пользователь нажимает на наше view. Информацию о нажатии мы передаем в наш «главный» контроллер через делагата. Этот контроллер с помощью анимации показывает нам таблицу выбора разделов и прячет ее, если мы выбрали раздел или снова нажали на середину navigation bar-a. Фантазировать на тему внешнего вида выпадающего экрана не хотелось, поэтому оставил по умолчанию. Белый фон, черный текст. В идеале, это надо все было бы заменить на соответствующий дизайнерский вид.

Хотя у нас и заранее подготовленные данные, я переживал, что очень большое количество прозрачности скажется на быстродействии скролла нашей основной таблицы. Чтобы все проверить, когда уже было закончено приложение, я запустил его на телефоне 4S и с помощью Instruments замерил FPS скролла. Он был не 60, но 57-58, что в принципе нормально, но уже сейчас мы видим просадку. Это еще раз нам говорит о том, что все-таки лучше стараться использовать непрозрачность где только возможно.

Снимок экрана 2014-06-20 в 16.43.11

Если вы выставите в свойствах проекта в разделе Apple LVVM 5.1 — Preprocessing параметр  NEW_THEME = 1, то увидите зеленый вариант приложения, о чем я вам говорил в самом начале этой статьи.

Снимок экрана 20 июня 2014 г., 15.47.31 с Симулятора iOS

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

Полный проект FancyTwitter к этой неделе на github.com

Маленькое видео с работой приложения:

До следующей недели!

Реклама

12 недель программирования и дизайна для iOS

Друзья, привет!

Давно придумал для себя одну штуку, но только сейчас дошли руки. Я полон желания довести дело до конца. Суть в следующем: каждую неделю я буду выбирать некий дизайн приложения с сайта dribbble.com и с согласия автора (а может и без) я пока не знаю, я буду писать именно этот экран (всего один) в коде, так чтобы все работало, как в настоящем приложении. То есть этот дизайн сойдет с экрана сайта в симулятор iOS и даже на экраны телефонов и планшетов, если у вас есть лицензия разработчика. Статью, описывающую код, я буду выкладывать сюда. А код на github. Так за 12 дней у нас соберется большая коллекция различных дизайнов приложений. В голове уже масса планов — и графики, и collection views, и реализация «скинов» для приложения, хотя Apple это не одобряет 🙂 короче много всего интересного.

Работать мы будем с iOS7, хотя этого немного уже устаревшая ОС 🙂 возможно, что-то ближе к сентябрю напишем и для iOS8. Формат, который бы мне был удобен такой, я сначала пишу целиком весь код, и не отвлекаюсь на написание статьи, а затем в статье рассказываю основные моменты, почему я сделал так или иначе. Так я сэкономлю время себе, да и вам, не рассказывая по порядку «берем вот эту view и тянем сюда, потом снова берем и тянем туда». Я кстати, сам очень люблю учиться именно на примерах. В свое время мне очень помогла именно такая книга.  Вот ссылка, но сейчас книга во многом устарела. Это сборник совершенно готовых рабочих программ. Мне кажется, такие примеры дают понимание, как отдельные элементы работают вместе.

На этой неделе мы начнем вот с этого дизайна. Дизайнер Александр Зайцев дал свое согласие на это мероприятие. Посмотрим, что из этого выйдет. Увидимся ближе к пятнице! Всем хорошей рабочей недели!

Дизайнер Александр Зайцев. Дизайн Твиттер клиента

С чем едят SUBQUERY

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

(SUBQUERY(residents, $x, $x.firstname == «Jane» && $x.lastname == «Doe»).@count != 0) (это как раз правильного subquery)

Оказывается все просто.

SUBQUERY(collection, variableName, predicateFormat)

Данная конструкция служит простой цели: когда мы хотим отфильтровать какой то набор данных (collection) по каким-то условиям. В данном примере мы ищем внутри коллекции residents людей с именем Jane Doe. Здесь надо остановиться и сказать, почему профессионалы против использования слово SUBQUERY. Просто потому, что его не надо использовать при каждом удобном случае. Core Data это не база данных и не средство управления базой данных. Это фреймворк со своей идеологией, и документацией ))) которую надо читать и изучать. Слово subquery не означает, что вы его должны постоянно использовать для запросов к Core Data — ведь для этого есть масса других более легких и быстрых методов.

Этот синтакис лучше всего использовать в одном и только в одном случае. Когда вам надо отфильтровать какую-то коллекцию объектов, каждый из которых связан с другой коллекцией объектов, по признакам которых (не менее двух) мы и хотим фильтровать. Вот тут коллега раскрывает все тайны волшебного слова SUBQUERY. Он пишет, что пусть у нас есть много объектов Project и к каждому из них есть куча объектов ToDo. И мы хотим найти все проекты, которые были выполнены Joey. Самое простое, что нам может прийти в голову это написать:

ANY todos.completionDate != nil AND ANY todos.user == Joey

, но тут нас подстерегает беда. Нам будут возвращены все записи joey и все записи с законченными todo. Мы не получим то, что нам надо. Тут нам на помощь и приходит SUBQUERY. Следующая запись уже вернет нам только нужные строчки.

SUBQUERY(todos, $todo, $todo.completionDate != nil AND $todo.user = ‘Joey’).@count > 0

Два других «нерабочих» варианта описаны в документации Apple.

For example, suppose you have an Apartment entity that has a to-many relationship to a Resident entity, and that you want to create a query for all apartments inhabited by a resident whose first name is «Jane» and whose last name is «Doe». Using only API available for Mac OS X v 10.4, you could try the predicate:

resident.firstname == "Jane" && resident.lastname == "Doe"

but this will always return false since resident.firstname and resident.lastname both return collections. You could also try:

resident.firstname CONTAINS "Jane" && resident.lastname CONTAINS "Doe"

but this is also flawed—it returns true if there are two residents, one of whom is John Doe and one of whom is Jane Smith. The only way to find the desired apartments is to do two passes: one through residents to find «Jane Doe», and one through apartments to find the ones where our Jane Does reside.

Subquery expressions provide a way to encapsulate this type of qualification into a single query.

Advanced iOS Programming

Получил по почте новости от сайта Big nerd Runch, про который я писал, что мне нравятся их книги. Увидел ссылку на их новый класс Advanced iOS Programming. Немного прифигел от ценничка в $4050, но вот программа мне очень понравилась. Поэтому я решил сам себя подтянуть прямо по ней по списочку.

  • Store documents, application data, and settings in iCloud
  • Write concurrent applications using Grand Central Dispatch and NSOperationQueue
  • Customize Storyboard view transitions
  • Use GLKit based controllers for OpenGL 3D rendering
  • Process and enhance images using Core Image and OpenGL ES shaders
  • Efficiently process data sets with the Accelerate framework
  • Asynchronously communicate with and parse data from JSON based web services
  • Post to Twitter and authenticate with other web services using the Twitter framework
  • Access the accelerometer, gyroscope and compass using Core Motion
  • Write Augmented Reality applications that place virtual markers on real-world objects
  • Record, process and playback audio in real time using Core Audio
  • Display and process real time video in OpenGL ES
  • Display content on external displays using AirPlay streaming and wired video connections
  • Use web views to render content and pass information and events between Javascript and Objective-C
  • Master the iOS performance optimization tools and LLDB debugger
  • Secure files on disk and credentials in the keychain

Начал с iCloud. Если что-то интересное по этим темам будет, то буду делиться 🙂

Книги по программированию для iOS. Часть 2

Вы возможно знаете, а возможно нет, что есть такая всемирно известная женщина-программист Эрика Садун (Erica Sadun). Она является постоянным автором популярного блога о TUAW.com А также постоянно пишет книги: начиная от сугубо «пользовательских», заканчивая серьезными книгами для программистов. 24 ноября выходит уже третье издание ее книги iOS Developer’s Cookbook — на этот раз The iOS 5 Developer’s Cookbook: Core Concepts and Essential Recipes for iOS Programmers. Кстати вот так коллеги представили Эрику на постере iPhone Wars.

Эта книга мне тоже очень нравится, хотя признаюсь целиком я ее не читал, да и не пытался. Потому что ее название — Cookbook, то есть поваренная книга. По сути это большой сборник рецептов, совершенно независимых друг от друга. Когда вам надо узнать как сделать кастомную клеточку в UITableView или написать метод определяющий скорость по GPS, как рисовать пальцем на экране, как проверить доступность сети в данным момент и еще сотни готовых рецептов. По каждому из них есть sample code, который вы можете скачать. Много примеров вообще написаны в виде всего одного файла кода в main.m чтобы не загружать вас деталями и не отвлекать от сути дела. Очень много трюков я почерпнул именно из этой книги. Ведь порой, когда ты изучаешь что-то новое, ты видишь готовый продукт и думаешь: «Хм… как это было сделано и как мне это повторить». Так вот Эрика отвечает на эти вопросы. Когда раньше я сталкивался с проблемой реализации какой-то идеи, то первым делом я лез в эту книгу.

Но сразу хочу оговориться, что это книга, как мне кажется, не для начинающих, хотя там и есть главы типа «Твой первый проект». Ее лучше всего использовать именно как книгу рецептов, когда вы знаете, что вы хотите, но не знаете КАК. Вот здесь вы можете посмотреть оглавление прошлого издания книги. Все примеры книги Эрика хранит всегда на github, и хотя новая книга еще не вышла, то код к ней уже давно там лежит.

Ну и на «сладкое»… как вы знаете в iOS 5 появился новый UIPageViewController — контроллер, который красиво переворачивает странички. И хотя Apple почему-то написали, что этот класс не предназначен для создания подкласса, Эрика наплевала на это и создала пример в своей новой книге и рассказала, как быстро и просто создать приложение с этим новым контроллером. Мне удалось меньше чем за час адаптировать его для своих нужд и сделать простенький фотоальбомчик. Поэтому если вам интересно, как использовать новый  UIPageViewController, то  попробуйте и вы — это просто! Примечательно, что какой-то человечек, прокомментировал этот код, сказав, что же вы делаете, Apple же не рекомендует так делать. На что Эрика ответила: «Спасибо, что вы поделились своим мнением» 🙂 Вот такая она, эта Эрика.

Книги по программированию для iOS. Часть 1

В последнее время наблюдается бум в изучении программирования для мобильных платформ. Особенно востребованными являются программисты для iOS. И часто первое, что набирает человек в строке поиска браузера, чтобы изучить новую для себя платформу, являются слова «objective-c», «ios», «iphone», «учебник». К сожалению книг на русском языке не так много, как бы хотелось. Об одной из них я уже писал тут. Но она рассказывает больше о самом языке программирования, а не о том как писать для iPhone. Сегодня я хочу рассказать о моей самой любимой книге, правда, на английском. Я считаю, что хотя бы технический английский надо знать обязательно. Тогда перед вами открываются все двери. Вы можете свободно общаться на форумах, вы можете смотреть обучающие видео с Apple WWDC, вы можете читать лучшие книги по программированию под iOS.

Итак, моя любимая книга в этой области это — iPhone Programming: The Big Nerd Ranch Guide. Да, вот такое у нее забавное название. Написали ее ребята из этой компании — Big Nerd Runch, которая уже занимается консалтингом и обучение в области программирования. Кстати, я подписался сегодня на их рассылку (кнопочка внизу страницы) и получил краткий лист самых важных сочетаний клавиш для Xcode4 в подарок. Мне понравилось 🙂 Чем же мне так понравилась эта книга? Тем, что с первых страниц книги мы начинаем сразу читать о том, что действительно важно в программировании под iOS. Есть такие книги, которые начинаются с прописных истин и только к середине вы как-то худо-бедно переходите к написанию Hello World, но читать дальше уже нет никаких сил. Так вот эта книга не такая. В этой книге с самого начала задается правильная идеология работы. Взять хотя бы то, что в первой главе нас сразу знакомят с паттерном Model-View-Controller, который является основным в проектировании приложений. В третьей главе четко и подробно расписана работа с памятью. Конечно, сейчас с введением в Xcode 4.2 технологи ARC это может показаться не актуальным, но я уверяю, это все еще важно. В следующей главе мы переходим к понятию delegate «делегатов», что тоже является ключевым моментом для понимания работы многих элементов интерфейса. И все это изучение идет на конкретных примерах приложений. В другой книге вы бы уже научились, возможно, большему числу «приемчиков», но без понимания, что стоит за той же UIButton, и как она работает.

У книге относительно недавно вышло второе издание, но ее можно смело читать и в первом.

Содержание книги — http://www.bignerdranch.com/documents/iOS_TOC.pdf

Как научиться рисовать даже программисту! :)

Допустим вы программист и решили написать игру для iOS. Вы даже уже придумали концепт и остались две маленькие тонкости — это нарисовать игру и написать игру. С написанием у вас проблем, наверное не будет: помучаетесь и напишите. А вот найти дизайнера, который будет вас понимать, особенно если вы ограничены в средствах,  будет сложновато. Поэтому дизайнер ChrisHildenbrand на прекрасном сайте Gamasutra уже выпустил три урока по рисованию для программистов. Причем для этого вам не понадобятся дорогие программы от компании Adobe. Вся работа будет вестись в бесплатных программах GIMP и Inkscape. Поэтому, если вы решили сами написать игру, да еще и сами ее нарисовать — эти уроки для вас. Итак, читаем и повторяем за автором.

Урок 1 — 2D Game Art For Programmers — Part 1

Урок 2 — 2D Game Art For Programmers — Part 2

Урок 3 — 2D Game Art For Programmers — Part 3

За апдейтами следите дальше сами 🙂