Как стать автором
Обновить

Комментарии 23

Позволю себе заметить, что в такой реализации о повороте экрана можно забыть: всё поедет. Поэтому нужно добавить необходимые констрейнты, а к тому же добавлять mainView не в окно, т.е.:

// вместо
[window addSubview:mainView];
// надо
UIView *view = [[window subviews] lastObject];
[view addSubview:mainView];

Тогда события смены ориентации будут приходить в mainView исправно. Кстати, весьма удобно вынести инициализацию UI в storyboard/xib и в синглтоне держать только указатель на view controller.

По статье в целом — неплохой туториал, много кому может пригодиться ;)
Спасибо! В задаче не было поддержки ориентации отличной от портретной, поэтому вот так сделали. Наш косяк, да.

Комментарий правильный! Нужно делать именно так.
Нет самого главного, свойства progress.
Если говорить про отрисовку, то вариантов масса. Я бы скорее всего отрисовал через CAShapeLayer, но если и использовать картинки, то здесь очевидно что можно использовать паттерн, который легко масштабирется и может быть любой длинны (UIColor colorWithPatternImage).
Если говорить об анимации, то не совсем понятно зачем столько блоков анимации фейдинга, когда с одними и теми же таймингами. И нет отмены анимаци, если необходимо перезапустить анимацию с другими параметрами, это когда дело дойдёт до конкретного использования данного класса.
И раз уж каждый раз создаются вьюшки после removeFromSuperview надо очищать переменную, которая ссылается на эту вьюшку.

Про стиль написания кода можно многое сказать, но всё же пару заметок:
— не надо использовать префикс k для констант и именование лучше делать по формуле ИмяКлассИмяКонстанты;
— не надо использовать define для констант, вместо этого: extern NSString *const BSBeautifulProgressBarManagerShowProgressBarNotification;
— приватные переменные _всегда_ реализовывать через свойства приватной категории;
— всегда использовать фигурные скобки в if, а то знаете что бывает (return return);
— флоат числа определять как флоат: 0.5f

Цель статьи какая?
1. Цель статьи — показать, что под капотом реально существующего проекта, да и некоторые вещи объяснить новичкам.
2. Про стиль написания кода можно очень (очень!) долго вести холивары, прошу от этого воздержаться.
3. Можно сделать очень многое и сильно улучшить этот код :) Спасибо за комментарии! Уверен, они помогут кому-нибудь улучшить наш подход.
Не стоит вопринимать слово стиль буквально, это уже давно намного больше чем просто выравние кода, хотя это тоже важно.
Слушайте, ну как это может быть этот код реального проекта, когда это просто болванка, которая по нотификешену показывает 15 секундную анимацию?
А как по Вашему работает progress bar при отправке imessage или sms? Обратите внимание, логика та же самая :)
Логика прогресс бара как раз не в том, чтобы показывать фейк 15 секунд, в результате которого пользователь может ничего не получить, а наоборот подтверить что работа идёт и он отображает данный прогресс. Для отправки SMS/iMessage используется несколько состояний прогресс бара:
1. Задачу менеджер отправки сообщений принял, определил в очередь и проверяет доступность сети/интернета.
2. Если связь есть, то в зависимость от типа связи соответствующие тайминги на прогресс отправки, но это не 100% прогресс бара.
3. Когда сообщение отправлено или связи нет включается финальная анимация завершения работы.
Т.е. когда мы через плохое соединение отправляем imessage и прогресс пробегает за 5 секунд, а потом еще секунд 20 висит почти в конце, это не фейк? Да, он не доходит до конца, но он не отображает реальный процесс отправки данных.
Думаю вы сами ответили на свой вопрос. В данной статье (предположим с плохим соединением) прогресс бар через 15 секунд покажет что задача выполнена 100%, но при этом экран полностью заблокирован. Такое приложение пользователи сочтут глюкавым и тормознутым. Вообще, не хорошо блокировать экран, когда можно выпонять задачу в параллельном потоке.
Сожалею, но Вы ошибаетесь. Чтобы закрыть прогресс бар, нужно вызвать у него метод hideProgressBar, и только тогда он добежит быстро до конца (если еще не добежал) и закроется. Если мы отправляем сообщение с плохим соединением, то прогресс бар закроется по окончанию отправки или по таймауту сети. Основная задача этого прогресс бара (так же как и при отправке смс) показать пользователю, что процесс отправки пошел, ему вовсе не нужно показывать реальное количество отправленных данных.
Блокировать экран не хорошо, с этим не поспоришь, это нужно просто дорабатывать/переделывать.
Кратенько напишу, что делает код выше:
1. Подписка на 2 нотификации: показать/скрыть прогресс бар, кстати нотификации абсолютно бесполезные, если мы говорим о синглтоне, в любом месте можно дёрнуть соотвествующий метод.
2. Показываем прогресс бар (showProgressBar)
2.1. Добавление затемнения и анимация 0.3 сек
2.2. Добавление белой плашки прогресс бара и анимация 0.3 сек
2.3. Добавление серого зипа к белой плашки
2.4. Добавление контейнера оранжего зипа и картинки оранжевого зипа (ох сколько вьюшек, хотя надо было использовать просто backgroundColor) и сразу же (!) анимация на 15 секунд.
3. Скрываем, если пришла нотификация
3.1 Анимация скрытия вьюшек за 0.3 сек (альфа и белая плашка вертикально)
И никаких быстренько потом добежать до конца нет.
Имелось в виду не добегание с помощью анимации, в 4 пункте в конце статьи «Кладем сверху новую оранжевую молнию». Это происходит очень быстро и визуально выглядит как добегание до конца.
Я понял о чем Вы говорите, да, нужно сделать чтобы прогресс не добегал до 100%, а останавливался на 90% примерно и ждал hideProgressBar, сейчас и правда выглядит не до конца понятно.
Да, как минимум.
Да, это — код социальной сети, написанной за 72 часа в рамках хакатона :)
Чем вам константы не угодили? Это общепринятый подход к их именованию в ObjC.
Год-два назад сам также именовал и всё ещё с ними работаю. Я всё понимаю, исторически сложилось. Но всё же это не в стиле Objective-C. В новых фрейворках iOS и в популярных open-source проектах видно что всё больше уходят от k префикса. А в итоге по работе скажу, что стало намного удобнее, когда сразу по имени класса начинаешь ввод и поиск константы. Если часто используете Open Quickly… (⇧⌘+O) то быстро можно привыкнуть к поиску констант без k.
Это все же не повод быть таким категоричным. Популярные open-source проекты — тоже не показатель :)
не надо использовать префикс k для констант и именование лучше делать по формуле ИмяКлассИмяКонстанты;

Я бы небыл столь категоричен в плане именования, в разных командах принято по разному и в этом ничего плохого нет.
не надо использовать define для констант, вместо этого: extern NSString *const BSBeautifulProgressBarManagerShowProgressBarNotification;

Да, вот с этим не поспоришь, так делать лучше

приватные переменные _всегда_ реализовывать через свойства приватной категории;

Здесь тоже нельзя быть категоричным, минус предложенного вами варианта — фейковая инкапсуляция, к такой проперти можно обратиться из вне. К переменной класса же(Помеченной как private) это сделать не на столько просто.

всегда использовать фигурные скобки в if, а то знаете что бывает (return return);

Это да, хорошая практика

флоат числа определять как флоат: 0.5f

Здесь тоже соглашусь
1. k префикс и константа — я не настолько категоричен к префиксу k сколько к именованию константы. Например kShouldShowBeautifulProgressBar: не хорошо называть константы, которые начинаются как ShouldShow… Во первых это похоже больше на булеву переменную. Во вторых это внешняя константа, а в этом пространстве имён огромное количество других констант и в objective-c так называемый namespacing строится от 2-х, 3-х и т.д. буквенного префикса соответствующего проекта/модуля для соответствующих классов, протоколов, констант и т.д. Константы от класса соответственно строятся от имени класса и смысловой нагрузки константы. Поэтому и получаем такую длинную константу примерно такую: BSBeautifulProgressBarManagerShowProgressBarNotification.

Правило для именования констант, енумов и блоков простое: чем больше область видимости, тем больше контекстной/родительской состовляющей, т.е. если константа в области видимости всего класса или даже внешняя, то добавляем имя класса как префикс. Константы внутри метода достаточно просто по имени. Почти тоже самое для имён переменных и методов. Обратный пример, если переменная живёт в области видимости 2-3-х строк, тогда её можно назвать очень кратко: i, frame, view, hidden и т.д.

Про k префикс это всё же рекомендация, будет проще и удобнее, поверьте. Но это по большей части рекомендация именно для objective-c.

2. Приватные переменные. Здесь мнительность совсем лишняя, что вообще-то можно всех обмануть и получить доступ к свойству. А важно это работа с ARC, KVO и многопоточностью. На WWDC неоднократно повторяют об использовании именно свойств через приватную категорию вместо приватных переменных.
это, про название переменных, вместо isShown использовать «visible» или «hidden»
Правильный комментарий! Спасибо за правки :)
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации