Результати пошуку за запитом: mvc 5*
Путівник ITVDN C#
Автор: Редакция ITVDN
C# занимает лидирующие позиции во всех рейтингах языков программирования. Так как рынок труда активно развивается, программисты, которые хорошо знают C# и технологии .NET, являются очень востребованными.
На ITVDN вы найдете все необходимое, чтобы выучить C# с нуля до профессионального уровня. Курсы записаны сертифицированными разработчикам и тренерами Microsoft.
Мы рекомендуем проходить обучение в такой последовательности:
C# Starter, автор Александр Шевчук
Выполнение домашних заданий по C# Starter, автор Константин Черный
How to C# Starter, автор Богдан Бондарчук
Тренажер по C# Starter
Visual Studio Tips & Tricks, автор Дмитрий Охрименко
C# Essential, автор Александр Шевчук
Выполнение домашних заданий по C# Essential, автор Константин Черный
How to C# Essential, автор Богдан Бондарчук
Тренажер по C# Essential
C# Универсальные шаблоны, автор Николай Мельничук
Unit Тестирование в C#, автор Дмитрий Охрименко
Асинхронное программирование в C# 5, автор Олег Кулыгин
C# для профессионалов, автор Александр Шевчук
How to C# Professional, автор Константин Черный
Что нового в C# 6.0-7.0, автор Александр Ткаленко
Также вас могут заинтересовать записи вебинаров ITVDN:
С# - с чего начать и как идти дальше?
Работа с Microsoft Word на C#
Если вы планируете свое обучение C# с нуля, тогда наилучшим решением будет приобретение подписки ITVDN сроком на 3 или 6 месяцев.
Тренди аутентифікації на 2017 рік
Автор: Редакция ITVDN
Настало время для прогнозов по безопасности и новым технологиям на следующий год. Ведь 2016 год стал еще одним годом, когда киберпреступность достигла новых высот, превысив прошлогодний набор угроз. Увеличение количества хакеров, новых технологий и выделение незначительных бюджетов для безопасности компаний создает идеальный плацдарм для более сложных хакерских механизмов. Одно можно сказать наверняка: вся эта буря, в свою очередь, привела к повышению осведомленности об угрозах кибербезопасности и появлению методов смягчения этих угроз.
Компании поняли, что, придерживаясь одинаковых стратегий безопасности, они не могут ожидать разных результатов. Их неспособность влиять на ход киберпреступности внутри организации является явным индикатором потребности в изменениях. В лучшем случае, самые везучие смогли замедлить и даже перенаправить атаки, но не остановить или значительно уменьшить их.
Правительства и компании, наконец, признали важность кибербезопасности и начали вкладывать большие деньги в защиту данных. Одно можно сказать наверняка: 2016 год был хорошим годом для признания кибербезопасности, поскольку была признана ее значительность.
Руководители отделов кибербезопаснсти, CISOs – Chief Information Security Officer, перешли к более активному подходу в этой сфере и сосредоточились на областях, которые могут контролировать. Главные их инициативы кибербезопасности в 2016 году (в США):
Источник: Исследование кибербезопасности Deloitte-NASCIO за 2016 год
В общей сложности 29% американских руководителей отделов IT-безопасности концентрируются на идентификации и управлении доступом (IAM), наиболее приоритетной является многофакторная аутентификация – 77%. Угрозы, направленные на сотрудников, такие как фишинг, фарминг, социальная инженерия и ransonware, больше всего беспокоят руководителей IT-безопасности.
И хотя задачи IT-безопасности являются первоочередными, CISOs по-прежнему сталкиваются с рядом преград при внедрении решений IAM внутри компании: затраты, законодательство, приоритеты компании и т.д.
Источник: Исследование кибербезопасности Deloitte-NASCIO за 2016 год
Тенденции аутентификации на 2017 год
Gartner определяет «аутентификацию пользователя» как подтверждение в реальном времени заявленной цифровой идентичности человека с подразумеваемым или условным уровнем доверия. Рынок аутентификации пользователей включает в себя несколько типов продуктов и услуг, которые позволяют реализовать множество методов проверки подлинности, которые направлены на сопровождение или удаление полностью классических систем на основе паролей.
Существуют 3 основных метода аутентификации:
Однофакторная аутентификация
Двухфакторная аутентификация
Многофакторная аутентификация
1. Однофакторная аутентификация (SFA)
Наиболее распространенной формой однофакторной аутентификации является аутентификация на основе пароля. Пароли существуют с первых дней работы компьютеров, около 55 лет. Пароль представляет собой непостоянную последовательность символов, используемых для определения того, что пользователь компьютера, запрашивающий доступ к компьютерной системе, действительно является конкретным пользователем. Естественно, что в такой быстро развивающейся среде, того, что использовалось 55 лет назад, уже недостаточно.
Пароли действительно являются самым слабым звеном в цепочке безопасности, и это связано с:
Невозможность людей придумать надежный пароль (они склонны недооценивать способность хакеров угадывать их пароли).
Склонность пользователей использовать один и тот же пароль для нескольких учетных записей (имея не менее 50 разных учетных записей, никто не может запомнить 50 разных паролей).
Способность хакеров взламывать их в считанные секунды.
Конечно, есть много менеджеров паролей, но даже эти инструменты иногда оказываются уязвимыми. Интерес к паролям не уменьшается - в целом поиск Google по слову «пароль» достаточно популярен, а это означает, что они по-прежнему являются основным методом аутентификации для большинства пользователей и систем.
Несмотря на последовательный интерес, на пароли охотятся сами создатели WWW, которые также создали консорциум под названием World Wide Consortium. Эта инициатива направлена на замену паролей более безопасными способами входа в веб-сайты, так как: «Сильная аутентификация полезна для любого веб-приложения, которое хочет поддерживать текущие отношения с пользователями». Учитывая все эти факты, мы заключаем:
Прогноз 2017: аутентификация на основе пароля будет переживать стагнацию.
Общая тенденция: стагнация.
Почему это может произойти:
- Рост заинтересованности людей в защите их частной жизни приведет к ускорению внедрения альтернативных аутентификационных механизмов.
- Пароли неэффективны в защите пользовательских аккаунтов.
- Как следствие разработки более сложных и безопасных систем аутентификации.
- Традиционный пароль будет ориентирован на более биометрический подход.
- Веб-сайты переходят к более безопасным механизмам входа.
Почему это может не произойти:
- Обычные пользователи в основном имеют базовые компьютерные знания и считают свои текущие пароли достаточно сильными.
- Все больше пользователей используют менеджеры паролей, сохраняя таким образом привычки входа с помощью паролей.
- Основная масса населения не считает свои данные «стоящими» усилий хакеров.
- При создании веб-сайтов используется классический механизм аутентификации пользователь/пароль.
2. Двухфакторная аутентификация (2FA)
Двухфакторная аутентификация – это в основном переход на традиционную аутентификацию на основе пароля, в результате которого добавлен дополнительный шаг к процессу входа в систему (второй фактор).
Двухфакторная аутентификация (2FA), часто называемая двухэтапной аутентификацией, представляет собой процесс безопасности, в котором пользователь предоставляет два фактора аутентификации, чтобы подтвердить, что он является тем, кем является, в отличие от однофакторной аутентификации (SFA), где пользователь предоставляет только один фактор – обычно пароль. 2FA существует уже довольно давно, но пользователи не выделяют ее как другую, иную систему аутентификации.
Интерес к этому типу аутентификации растет довольно резко, поскольку поисковые запросы Google для термина «двухфакторная аутентификация» растут, особенно во второй половине 2016 года.
Одной из наиболее распространенных форм двухфакторной аутентификации является форма, основанная на SMS, поскольку она во многом используется большинством финансовых учреждений. Широко распространенная версия 2FA на основе SMS теперь считается небезопасной из-за того, что они отправляются через различные небезопасные системы и существует риск перехвата SMS-сообщений со стороны нежелательных сторон.
Национальный институт стандартов и технологий Министерства торговли США опубликовал проект, содержащий новые рекомендуемые стандарты аутентификации. В этом проекте предлагаются другие методы проверки подлинности, кроме основанных на SMS: «OOB с использованием SMS устарел и больше не будет разрешен в будущих версиях этого руководства».
Прогноз 2017: использование двухфакторной аутентификации будет возрастать.
Общая тенденция: увеличение.
Почему это может произойти:
- Переход от аутентификации с помощью пароля к двухфакторной аутентификации сравнительно легок, так как это добавляет один проверочный шаг в процесс.
- Главные компании, такие как Apple, Google и Facebook, уже внедрили ее, познакомив своих пользователей с этой новой технологией и ускоряя внедрение.
- Так как 2FA будет получать большую поддержку во внедрении, уязвимости будут ликвидированы и число компаний, внедряющих эту технологию, будет расти.
Почему это может не произойти:
- Двухфакторная аутентификация по-прежнему основана на паролях для аутентификации, к которым добавляется дополнительный проверочный шаг.
- Так как аутентификация с помощью SMS теряет популярность как небезопасная, это может повлиять на общий рост 2FA.
- Пользователи стойки к 2FA системам до их внедрения, что часто заставляет их менять используемые сервисы. Однако, как только система внедрена или становится обязательной, стойкость значительно падает.
3. Многофакторная аутентификация (MFA)
Более надежной альтернативой двухфакторному механизму аутентификации является многофакторная аутентификация. Многофакторная аутентификация (MFA) – это система безопасности, которая требует более одного метода аутентификации из независимых учетных данных для проверки личности пользователя при входе или другой транзакции.
MFA создает многоуровневую систему защиты, которая усложняет работу хакеров, поскольку им придется взломать все независимые учетные данные:
То, что пользователь знает (пароль)
То, что у пользователя есть (маркеры безопасности)
Что-то от пользователя (биометрическая проверка)
В поиске Google термин «многофакторная аутентификация» не имеет резкого увеличения, как в случае с 2FA, но видна устойчивая ритмическая эволюция.
В отчете, опубликованном Markets And Markets, показано, что рынок мультифакторной аутентификации по прогнозам превысит 9,6 млрд. долл. США, применяемый в разных областях (путешествия и иммиграция, правительство, банковское дело, оборона, коммерция, безопасность, бытовая электроника, здравоохранение).
Источник: MarketsandMarkets
Помимо высокого уровня безопасности, многофакторная аутентификация обеспечивает определенную степень гибкости, позволяя компании устанавливать желаемый уровень безопасности в зависимости от профиля пользователей и потребностей.
Прогноз 2017: многофакторная аутентификация будет неуклонно расти.
Общая тенденция: увеличение.
Почему это может произойти:
- Так как проблемы безопасности возрастают, компании и правительства будут искать более сложные аутентификационные системы, такие как MFA.
- MFA намного безопаснее, чем 2FA, которая до сих пор сильно зависит от паролей для аутентификации.
- Учитывая уровень безопасности, который имеет MFA, она превосходит по удобству 2FA.
- Законодательство – это важный фактор, который положительно влияет на рост рынка MFA, так как появляются законодательные требования по охране данных.
- Правительства выделяют крупные суммы для создания продуктов кибербезопасности.
Почему это может не произойти:
- Осведомленность о кибербезопасности все еще низкая среди компаний и сотрудников.
- Организации имеют ограниченный бюджет, навыки и ресурсы для усиления кибербезопасноти, что замедляет ее внедрение.
- Длинные и часто сложные финансовые процессы компаний, ориентированных на кибербезопасность и создающих аутентификационные продукты.
Поскольку мир все больше озадачен сохранением конфиденциальности и защиты данных из-за повышения количества взломов, компании и правительства вынуждены придумывать более эффективные инструменты кибербезопасности. На эволюцию рынка этой отрасли влияют несколько факторов: удобство использования, осведомленность о безопасности и спрос на нее, бюджеты и законодательство.
Источник: https://www.upwork.com/hiring/for-clients/authentication-trends/
Огляд функцій у JavaScript ES6
Автор: Adrian Mejia
В течение последних нескольких лет JavaScript изменялся. И вот 12 новых фичей, которые вы можете начать использовать уже сегодня!
1. История JavaScript
Новые дополнения к языку называются ECMAScript 6. Они также упоминаются как ES6 или ES2015+. Начиная с концепции 1995 года, JavaScript развивался медленно. Новые дополнения выходили раз в несколько лет. ECMAScript появился в 1997 году, чтобы указать путь JavaScript. Были выпущены такие его версии: ES3, ES5, ES6 и другие.
Как вы заметили, между ES3, ES5 и ES6 существуют промежутки в 10 и 6 лет. Новая стратегия состоит в том, чтобы делать небольшие постепенные изменения каждый год. Вместо того, чтобы делать большие изменения сразу, как это случилось с ES6.
2. Поддержка браузеров
Все современные браузеры и среды программирования уже поддерживают ES6!
Chrome, MS Edge, Firefox, Safari, Node и многие другие уже имеют встроенную поддержку большинства функций JavaScript ES6. Таким образом, всё, что вы собираетесь изучить в этом туториале, вы можете начать использовать прямо сейчас. Давайте начнем с ECMAScript 6!
3. Основные функции ES6
Вы можете проверить все эти фрагменты кода на консоли своего браузера.
Так что не верьте мне на слово и тестируйте каждый пример ES5 и ES6.
3.1. Блочная область видимости переменных
В ES6 мы перешли от объявления переменных с var на использование let/const.
Что не так с var? Проблема var – это утечка переменной в другой блок кода, например, в циклы for или if-блоки.
Для test(false) вы ожидаете возвращения outer, но нет, вы получаете undefined. Почему?
Потому что даже при том, что if-блок не выполняется, выражение var x в строке 4 «поднимается».
Поднятие переменных:
var является переменной области видимости. Она доступна во всей функции даже до того, как её объявят.
Выражения «поднимаются». Так что вы сможете использовать переменные до их объявления.
Инициализация НЕ поднимется. Если вы используете var, ВСЕГДА объявляйте ваши переменные наверху.
После применения правил подъема, мы можем лучше понять, что же случилось.
ECMAScript 2015 идёт на помощь:
Изменение var на let приводит к тому, что всё работает так, как и ожидалось. Если блок if не вызывается, переменная x не поднимается из блока.
Взглянём на поднятие и «временные мёртвые зоны»:
В ES6 let будет поднимать переменную наверх блока (НЕ наверх функции, как это происходит в ES5).
Однако ссылка на переменную в блоке перед объявлением этой переменной приводит к ReferenceError.
let – переменная области видимости. Вы не можете использовать её, пока она не будет объявлена.
«Временные мёртвые зоны» – это зоны в начале блока и до того места, где объявляется переменная.
IIFE (Immediately-Invoked Function Expression)
Перед объяснением IIFE взгляните на пример:
Как вы видите, появляется private. Для того, чтобы удержать его, вам необходимо использовать IIFE (немедленно-вызываемое выражение функции):
Если вы посмотрите на jQuery/lodash или другие open source проекты, то заметите, что они используют IIFE во избежание загрязнения глобальной среды и определения только глобального, например _,$ или jQuery.
ES6 гораздо проще, нам больше не нужно использовать IIFE, когда мы просто можем применить блоки и let:
Const
Вы также можете использовать const, если не хотите, чтобы переменная изменялась вообще.
3.2. Литералы шаблонов
Нам больше не нужно встраивать конкатенации, когда у нас есть литералы шаблонов. Взгляните:
Сейчас вы можете использовать кавычку (`) и строковую интерполяцию ${}:
3.3. Многострочные строки
Нам больше не нужно конкатенации строк + \n по типу:
В ES6 мы снова можем использовать кавычку для решения такого примера:
Оба фрагмента кода будут иметь точно такой же результат.
3.4. Назначение деструктуризации
Деструктуризация в ES6 очень полезная и точная.
Получение элементов с массива
То же самое:
Обмен значений
Так же:
Деструктуризация для нескольких возвращаемых значений
В строке 3 вы также можете вернуть ее в массив подобный тому, что на примере (и сохранить некоторые, набрав код):
Но потом необходимо подумать о порядке возврата данных.
В ES6 вызывающий выбирает только те данные, которые ему нужны (строка 6):
Обратите внимание: В строке 3 есть некоторые другие функции ES6. Мы можем сжать { left: left} только до { left}.Посмотрите, насколько это компактнее по сравнению с версией ES5. Разве не круто?
Деструктуризация для параметров согласования
Так же, но короче:
Deep Matching
Так же, но короче:
Это также называют деструктуризацией объектов.
Как видите, деструктуризация весьма полезна и способствует хорошему стилю программирования.
Практический опыт:
Используйте деструктуризацию массива для получения элементов или замены переменных. Это избавит вас от создания временных ссылок.
Не используйте деструктуризацию массива для нескольких возвращаемых значений, вместо этого примените деструктуризацию объекта.
3.5. Классы и Объекты
С ECMAScript 6 мы перешли от «функции-конструктора» к «классам».
В JavaScript каждый отдельный объект имеет прототип, который является другим объектом. Все объекты JavaScript наследуют свои методы и свойства от своего прототипа.
В ES5 мы использовали объектно-ориентированное программирование (ООП), применяя функцию- конструктор для создания объектов, следующим образом:
В ES6 имеется некий синтаксический сахар. Мы можем делать то же самое менее шаблонно и с новыми ключевыми словами, такими как class и constructor. Также обратите внимание на то, как мы определяем методы constructor.prototype.speak = function () vs speak():
Как видим, оба стиля (ES5/6) дают одинаковые результаты и используются одинаково.
Практический опыт:
Всегда используйте синтаксис класса и избегайте прямого манипулирования прототипом. Почему? Потому что это делает код более кратким и понятным.
Избегайте наличия пустого конструктора. Классы имеют конструктор по умолчанию, если он не указан.
3.6. Наследование
Опираемся на предыдущий класс Animal. Предположим, мы хотим расширить его и определить класс Lion.
В ES5 это большей частью связано с прототипическим наследованием.
Я не буду описывать все детали, но заметьте:
В строке 3 мы явно вызываем конструктор Animal с параметрами.
В строках 7-8 мы назначили прототип Lion прототипу Animal.
В строке 11 мы вызываем метод speak из родительского класса Animal.
В ES6 у нас есть новые ключевые слова extends и super.
Посмотрите, насколько разборчиво выглядит этот код ES6 по сравнению с ES5, и они работают одинаково!
Практический опыт:
Используйте встроенный способ наследования с extends.
3.7. Native Promises
Мы перешли от callback hell к promises.
У нас есть одна функция, которая при done получает обратный вызов для выполнения. Мы должны выполнить этот вызов дважды один за другим. Вот почему во второй раз мы вызываем printAfterTimeout.
Правда, это может пойти наперекосяк, если вам нужен третий или четвёртый обратный вызов. Давайте посмотрим, как мы можем сделать это с промисами:
Как видите, мы с промисами мы можем использовать then, чтобы сделать что-либо после выполнения другой функции. Больше не нужно хранить вложенные функции.
3.8. Стрелочные функции
ES6 не удалил выражения функций, но добавил новые функции – стрелочные.
В ES5 были некоторые проблемы с this:
Вам нужно использовать временное this для ссылки внутри функции или использовать bind. В ES6 вы можете использовать стрелочную функцию.
3.9. For…of
Мы перешли от for к forEach, и потом к for…of:
В ES6 for...of также позволяет нам делать итерации.
3.10. Параметры по умолчанию
Мы перешли от проверки того, была ли переменная определена, к присвоению значения параметрам по умолчанию (default parameters). Вы делали что-то подобное раньше?
Вероятно, это обычный шаблон для проверки того, имеет ли переменная значение или присваивает значение по умолчанию. Однако заметьте, что здесь есть некоторые спорные вопросы:
В строке 8 мы задали 0, 0 и получили 0, -1
В строке 9 мы задали false, но получили true.
Если в качестве параметра по умолчанию задано значение boolean или это значение равно нулю, то оно не будет работать. Знаете почему? Все расскажем после примера ES6. С ES6 вы можете писать код лучше и короче!
Обратите внимание на строки 5 и 6 – мы получаем ожидаемые результаты. Пример ES5 не работает. Сначала мы должны проверить undefined, поскольку false, null, undefined и 0 являются фальшивыми значениями. Мы можем выбраться с такими цифрами:
Сейчас всё работает так, как и должно, когда мы проверяем undefined.
3.11. Rest-параметры
Мы перешли от аргументов к rest-параметрам и spread-оператору. Получать произвольное количество аргументов на ES5 довольно неудобно:
Мы можем сделать то же, используя rest-оператор . . . .
3.12. Spread-оператор
Мы пришли от apply() до spread-оператора. Опять на помощь приходит . . .:
Напоминание: мы используем apply () для преобразования массива в список аргументов. Например, Math.max () принимает список параметров, но, если у нас есть массив, мы можем использовать apply, чтобы заставить его работать.
Как мы видели ранее, мы можем использовать apply для передачи массивов в виде списка аргументов:
В ES6 вы можете использовать spread-оператор:
Кроме того, мы пришли от использования массивов contact к использованию spread-оператора:
В ES6 вы можете сглаживать вложенные массивы, используя оператор spread:
4. Заключение
JavaScript прошёл через множество изменений. В этой статье описываются основные функции, которые должен знать каждый разработчик JavaScript. Кроме того, в статье есть примеры из практического опыта, которые помогут сделать ваш код более кратким и простым для понимания.
Материал подготовлен на основе статьи из блога Adrian Mejia
Java Developer: плануємо навчання правильно
Автор: Редакция ITVDN
Ваша цель - стать Junior Java developer в кратчайшие сроки? Что, если мы скажем вам, что её можно достичь всего за шесть месяцев? Хотите узнать - как? Внимательно читайте статью и следуйте рекомендациям.
Мотивация
Итак, первый и, наверное, самый важный шаг – это мотивация. Как всем известно, под лежачий камень вода не течёт. Так что нужно чётко сформулировать свою цель и уже сейчас начать что-то делать для её достижения. Но прежде чем начинать действовать, честно спросите себя: «Зачем я делаю это? Действительно ли мне это нужно?». Ведь без понимания значимости того или иного занятия, не будет и желания работать.
Не можете понять, действительно ли это ваша цель? Лучшим мерилом того, насколько вы хотите получить желаемое, является то, что вы готовы отдать за него. Готовы ли вы тратить, допустим, 10 или 20 часов в неделю на изучение Java? Если ответ отрицательный, то с рациональной точки зрения вам следует отказаться от этой цели. Потому что, если вы уделяете этому по 5-7 часов в неделю, вы просто тратите время впустую. Аналогично и с деньгами: если вы не готовы тратить их на изучение Java, скорее всего, вы не сильно верите в то, что вам это нужно.
Так что чётко определяйте цель, осмысливайте её значимость для вас и начинайте действовать!
Периоды
В становлении джава-программиста условно можно выделить три периода:
До резюме
Во время резюме
После резюме
«До резюме» - это тот период, когда ещё не следует рассылать свое резюме, но создать его нужно. Резюме – своего рода рекламный буклет, в котором записаны ваши цели и желания. То есть в нём вы даёте себе чёткую задачу того, чего хотите. И чем раньше вы поймёте свои желания, тем быстрее вы получите результат.
«Во время резюме» - это период, когда вы уже имеете достаточно знаний и рассылать резюме можно. На данном этапе вам следует пересмотреть ранее созданное, адаптировать его и обновить. Вообще такие действия с резюме стоит проводить раз в одну-две недели. И прежде чем отсылать резюме, его, конечно же, нужно привести в как можно более актуальное состояние. Важно отметить, что именно в этот период вы набираетесь бесценного опыта. Так как в это время вы начинаете ходить на собеседования и набивать свои первые шишки, без которых никак не обойтись.
«После резюме» - период, когда вы уже устроились на работу и ни о чём не беспокоитесь.
Не забываем об eXtreme Practices
Для монетизации себя как специалиста, вам просто необходимо познакомиться с экстрим-практиками. «Что же это за практики такие экстремальные?» - спросите вы. Экстремального с точки зрения опасности для жизни в этих практиках очень мало. Одними из самых популярных практик считаются TVD, парное программирование, непрерывная интеграция, рефакторинг и другие. Но вы можете вырабатывать и свои практики. Просто попробуйте понаблюдать за собой в процессе работы и отметьте, что сильнее всего вам помогает в достижении конкретной цели. На базе этих наблюдений вы сможете создать практику, которая подойдёт вам наилучшим образом.
Ещё один хороший способ улучшить свою работу – ретроспектива. Регулярно проводите её и анализируйте свои действия в профессиональной сфере. Пересматривайте вопросы, задаваемые вам на собеседованиях, и свои ответы на них. Это нужно делать для того, чтобы проверять себя на соответствие потребностям рабочего рынка.
Вводите метрики рабочих часов, пройденных курсов или тем из них. Благодаря этому вы сможете видеть и контролировать то, сколько своих ресурсов вы потратили на обучение. Такой подход покажет вам честную картину вашей работы.
Как учиться?
Для освоения чего-либо существует множество возможностей. Вам только нужно найти свой способ и приступать к обучению. Давайте детально разберём несколько методов, чтобы вы смогли понять, какой из них подойдёт вам лучше всего.
Онлайн тренинг
В последнее время большой популярностью пользуются онлайн-тренинги. Главный их плюс состоит в том, что для них создана конкретная программа, и вы имеете доступ к ней в любое время в любом месте. Но к выбору тренинга нужно подходить с большой ответственностью. Стоит очень внимательно выбирать программу и учитывать, кто ведёт тренинг. К минусам такого метода обучения, во-первых, можно отнести большую вероятность того, что вы не пройдёте тренинг до конца, а во-вторых - отсутствие общения с тренером и такими же учащимися, как и вы.
Если вы всё же решили обучаться таким способом, то верным вариантом не забросить это дело будет найти кого-то, перед кем можно будет отчитываться о проделанной работе или проходить тренинг в паре с другом. Также вы можете заключить пари с кем-то из знакомых или в социальных сетях, и тогда вам будет сложно отвертеться от начатого.
Офлайн тренинг
Такие тренинги ограничены местом и временем, что бывает не очень удобно, а также в большинстве своём они платные. Но посещая их, вы лучше и быстрее усваиваете материал, так как общаетесь с тренером вживую. На офлайн тренинге вы имеете возможность работать в команде над проектом, который в дальнейшем можно будет разместить, например, на GitHub и создать некую точку контакта с рекрутерами. Хотя в этом плюсе есть свои минусы, потому что если вы пропустите несколько занятий, то вам будет сложно успевать за командой.
Обучаясь на офлайн тренинге, вам нужно будет готовиться к встречам, выполнять задания и приходить с вопросами к тренеру – так вы получите максимальную пользу от учёбы. На тренинге вы также имеете возможность найти напарника, с которым идти по пути к цели будет проще, или целую команду, что дает надежду на работоустройство после окончания обучения.
Платные курсы
Сам факт того, что вы платите кому-то деньги, должен гарантировать некий стандарт качества и честность оказания услуг. Обычно учебные центры, в которых создаются эти курсы, заинтересованы в качестве и поддержании своей репутации. Поэтому такой способ обучения достаточно эффективен и, к тому же, существует большая вероятность того, что вы окончите курс, так как уже заплатили за него. Если вам подходит такой метод, то к выбору курса стоит отнестись осознанно и трижды подумать, прежде чем отдавать деньги.
Учтите, что оплата – это благодарность авторам курса, ответственность за результат всё равно лежит на вас. Ведь каким бы хорошим не был тренер на курсе, в его обязанности не входит учиться за вас, вы должны делать это сами.
Собственный проект
Учиться, создавая собственный проект – это очень смело, и очень круто. Но вы должны быть готовы к любым трудностям. Используя этот метод, для достижения успеха вам необходимо решать актуальные задачи. Начните создавать, например, консольный проект с мыслью о том, что он скоро станет веб-интерфейсом. Реализовывайте в этом проекте всю полученную вами информацию по этой теме, оттачивайте свои умения! Помните, что главное – не результат, а процесс. Потому как именно в процессе вы набираетесь знаний и опыта.
Персональный коучинг
При таком способе обучения с вами работает более квалифицированный специалист и решает вашу конкретную задачу. Занимаясь персонально, вы получаете индивидуальный, сделанный под вас план и выгодное знакомство. Согласитесь, никому не помешает знакомый человек из той сферы, в которой вы хотите реализоваться. Правда, у этого метода есть один минус – нанимать личного тренера зачастую стоит больших денег. Но если вы настроены серьезно и верите в поставленную перед собой цель, то это не должно быть преградой.
Тренинг в компании
Обучаясь в компании, вы получаете максимальный результат минимальными усилиями. Такие тренинги, как правило, бесплатные, а после их успешного окончания вы получаете возможность устроиться на работу в эту же компанию. Программы тренингов всегда адаптированы под компанию, что убережёт вас от изучения ненужного и бесполезного. Но на эти тренинги всегда очень большой конкурс, и при отборе вам необходимо проявить себя наилучшим образом.
Самостоятельно
Этот способ требует минимальных инвестиций и максимальной отдачи. Перед тем, как приступать к самостоятельному обучению, стоит составить учебный план. Распишите все курсы и темы, которые вы хотите пройти, распределите их по пунктам и приоритетности. Не забывайте вести учёт времени по каждому из пунктов и следить за статусом каждого из них.
Выбрав самообучение, вы становитесь на непростой путь и рискуете не дойти до конца. Тем более, что сегодня вы имеете доступ к огромному количеству информации, среди которой очень просто потеряться. Но если вы всегда готовы к борьбе с трудностями и не привыкли отступать, то сможете научиться чему-либо самостоятельно. Систематически занимайтесь, создавайте свои проекты, найдите себе напарника по учёбе, и вы обязательно добьетесь успеха.
Каким должен быть JavaJunior?
Естественно, джуниор должен хорошо знать язык и решать алгоритмические задачи. Вы должны понимать ООП и уметь моделировать. Знание коллекций, input/output и умение писать юнит-тесты только приветствуется. Также неплохо было бы выучить какой-то из фреймворков и понимать веб-сервисы. Но это всё от вас потребуется не сразу. Некоторые из вышеперечисленных и другие навыки вы получите непосредственно в ходе самой работы.
Создание и распространение резюме
В интернете вы можете найти множество советов по составлению резюме, но всё же давайте обговорим некоторые моменты, что касаются этого дела. Итак, при написании резюме вам необходимо придерживаться порядка, который присущ данному виду документа и, конечно же, писать грамотно. Свой опыт работы стоит записывать в обратном хронологическом порядке и указывать только правдивую информацию, хотя слегка её приукрасить можно. То, что резюме нужно составлять в деловом, корректном стиле - понятно само собой.
Хорошо, вы написали резюме. Теперь, чтобы начать поиск работы, вам необходимо его разослать. С этим у вас не должно быть проблем. Присылайте свое резюме известным и не очень IT-компаниям. Поместите его на сайтах поиска работы, благо сейчас таких много. Не стесняйтесь использовать социальные сети и разные сообщества для поиска работы. Главное - быть настойчивым и не лениться, тогда всё сложиться так, как вы того хотите.
Техническое собеседование
Отлично! Ваше резюме подошло, и вас позвали на собеседование в компанию. Как же к нему подготовиться? В первую очередь, вы должны соответствовать требованиям вакансии и показать навыки, описанные в резюме. По возможности, просите проведения собеседования утром, так как за целый день можно забить себе голову всяким и под вечер прийти никаким. Тем более доказано, что в первой половине дня человеческий мозг работает лучше. И да, в день собеседования не вздумайте доучивать то, что не выучили раньше - это только навредит вам. Будьте спокойны, не паникуйте. Ведь беспокойство сбивает с толку и уничтожает пунктуальность. Поэтому расслабьтесь и наберитесь уверенности.
На собеседовании общайтесь грамотно. Согласитесь, что человек, разговаривающий грамотно, вызывает больше доверия и вести беседу с ним приятнее. Кстати, немного о ходе беседы. Не загоняйте себя в глухой угол, не стоит говорить о тех вещах, в которых вы не разбираетесь. Этим вы можете ухудшить ситуацию и произвести неправильное впечатление. Также следует внимательно слушать своего собеседника. Таким образом вы покажете, что умеете прислушиваться к людям и работать в команде.
Вывод
Всё только начинается! Если вы дочитали эту статью до конца – поздравляем! Значит, вы решительно настроены и собираетесь достичь поставленной перед собой цели. Будьте Человеком-Решением, а не Человеком-Проблемой, и тогда перед вами откроется множество дверей. Не сворачивайте с намеченного пути, продолжайте учиться и развиваться. Помните, что всё в вашей жизни зависит только от вас. Так что уж постарайтесь сделать всё наилучшим образом.
4 найкращі блоги з front-end розробки
Автор: Anita Soczka
Интернет, а соответственно и сфера веб разработки, быстро и постоянно изменяется. Если ты front-end разработчик, тогда скорее всего, ты знаешь, что нужно быть в курсе новостей (уж поверь!), уметь работать с новыми инструментами, тенденциями и бизнес-процессами. Все самое важное ты сможешь найти в Интернете, но будь осторожен, поскольку в сети много ненужного мусора. Какие же блоги по front-end технологиям наилучшие?
Ежедневно публикуются сотни постов и статей. Все они беспорядочны и можно сойти с ума, пытаясь поспеть за всем. Прочитать их все просто невозможно. Более того, не нужно читать все в подряд. Именно поэтому я попросил людей из компании Merixstudio выделить лучшие технические блоги по front-end разработке, которые стоит читать, и они собрали лучшие ресурсы новостей и тенденций в мире веб разработки.
Ранее я уже публиковал статью о самых влиятельных блогах, ориентированных на технологии и веб разработку в целом. На этот раз буду подробно рассказывать о лучших front-end ресурсах (порядок сайтов случайный).
Speckyboy
Сайт позиционирует себя как журнал веб дизайна, но Paul Andrew – основатель Speckyboy – концентрируется не только на дизайн-ресурсах, но также предоставляет полезную информацию о новейших веб технологиях. Блог, безусловно, является отличным источником информации для ежедневного использования front-end разработчиком – блог предлагает отличные посты, справочники, разные источники информации и мотивирующий контент со всего мира.
• #11,771 по рейтингу Alexa Rank*
• 54,143 подписчиков на Facebook
• 75,150 подписчиков на Twitter
CSS-Tricks
Если ты хочешь улучшить свои навыки в области веб дизайна и веб разработки, тебе стоит подписаться на CSS-Tricks, который ведет интернет-гуру Chris Coyier. Это кладезь знаний по веб разработке, который непременно повысит уровень представляемого тобой веб контента. CSS-Tricks в основном фокусируется на темах, связанных с CSS. Блог предоставляет фрагменты кода, «прорывные» статьи, видео, учебные курсы, подкасты и многое другое.
• #1,253 по рейтингу Alexa Rank*
• 67,776 подписчиков на Facebook
• 298,126 подписчиков на Twitter
Codrops
Codrops можно назвать одним из самых новых и быстро растущих сайтов с документацией в сфере информационных технологий. Каждый front-end разработчик и веб дизайнер может найти много полезных материалов и фрагментов кода на Сodrops. Он также охватывает общие темы веб-разработки и веб-дизайна. Блог ведется всего лишь двумя дизайнерами – фанатами своего дела – Manoela Ilic и Pedro Botelho. Ко всем преимуществам блога можно добавить красивое оформление сайта. Этот блог стоит посещать, чтобы обучаться новым хитростям и тенденциям в индустрии.
• #3,197 по рейтингу Alexa Rank*
• 89,619 подписчиков на Facebook
• 164,845 подписчиков на Twitter
Todd Motto’s blog
Todd работает на позиции Developer Advocate в компании Telerik. Todd – основатель Ultimate Angular, а также Developer Expert в Google, спикер на конференциях и сторонник проектов с открытым кодом. В целом, он пишет на Angular и JavaScript. Его самоуверенный гид по командному стилю работы с AngularJS приобрел очень большую популярность на Reddit и Hacker News. Его блог отличный ресурс для подпитки собственных знаний, особенно, если ты заинтересован именно в таких технологиях, как Angular и JavaScript.
• #44,788 по рейтингу Alexa Rank*
• 1140 подписчиков на Facebook
• 30,396 подписчиков на Twitter
Очень важно, чтобы ты нашел свой собственный, уникальный способ отслеживать нужную тебе информацию. Так что, читай книги, журналы, отслеживай в Twitter людей, которые создают новые тенденции, смотри видеоматериалы, посещай конференции, общайся с единомышленниками и создавай новое!
*Alexa Rank – глобальный рейтинг трафика, учитывающий, как число посетителей, так и число просмотров страниц. Предоставляется компанией Alexa Internet.
Оригинал: www.merixstudio.com.
10 секретів ідеального коду
Автор: Nicolas Baptiste
Взято с настоящего поля битвы: работы
Спустя практически 10 лет работы на Javascript мне захотелось поделиться своими ежедневными секретами написания кода. Многие советы были позаимствованы у моих коллег, из книг или видео. Такие приёмы не должны оставаться в тайне, поэтому я ими и хочу поделиться!
1. Меньше кода = меньше багов
Это может прозвучать тривиально, но всегда держите это в уме. Любую часть можно убрать, даже не сомневайтесь! Просто удалите. Неработающий код, неиспользуемые переменные, лишние скобки: каждый малейший знак учитывается.
2. Развивайте читабельность кода
Это дополнение к пункту 1. Если хочется сократить код, всегда нужно помнить о том, что рано или поздно код будет прочитан другими людьми. Может, кто-то другой, может, через несколько месяцев, но будет очень неприятно, если придется потратить больше времени на разбор кода, чем было потрачено на его написание. Запомните: код всегда важнее, чем комментарии или документация.
Следите за переменными и именами функций, они должны быть достаточно наглядными, чтобы потом не объяснять их в комментариях.
3. Не пугайтесь функций, возвращающих функции
Когда я начал кодить на javascript, мне не нравился метод написания кода с использованием функций, возвращающих функции, потому что, казалось, этому сложно следовать в процессе выполнения. Но этот шаблон, довольно мощный и часто используемый, называется замыканием. Это действительно полезная функция и, как только вы используете её, она значительно облегчает структуру кода. И это первый шаг для погружения в функциональное программирование.
4. Извлекание частей
Функция становится слишком большой? Сделайте из нескольких частей отдельные функции! Не совсем понятно? Выделите их в переменную и дайте ей понятное имя. Такой метод, конечно, схож со вторым пунктом, но это сделает ваш код более читабельным. А знаете ли Вы, что Ваша среда разработки может помочь? Ctrl + alt + v выражение извлекается в Webstorm и потом выделяется в переменную. Ctrl + alt + m сделает из него функцию.
5. Переверните мышление
Это первый шаг перед TDD. Скорее всего, вы всегда знаете, чего хотите достичь. Так начните с конца, напишите ожидаемый результат и пишите код в обратном порядке, чтобы получить то, что хотите. Если будете писать в прямом порядке, вероятней всего, Вы начнете писать и проверять, работает ли оно. Поменяйте, проверьте, напишите что-то другое, проверьте и…. Возможно, это даже не особо полезно для достижения Вашей цели. Но такое мышление поможет сфокусироваться и потратить меньше времени.
6. Исключите условные операторы
Если для функции у вас на уме принцип единственной ответственности, условным операторам тут не место. Они создают ветвления в потоке выполнения. И один маленький if позволит другим разработчикам добавить всё больше логики в него. Я считаю, что условные операторы if вообще не должны использоваться без else, а их размещение внутри другого условного оператора нужно полностью запретить! Опять же, такой подход делает код более сложным, и часто оказывается, что функция выполняет больше, чем нужно. Как же от этого избавиться? Смотрите следующий пункт.
7. Используйте lodash_.get вместо проверки null/undefined
Очень часто, анализируя код, я вижу использование ifs для проверки null или undefined значений. Но без использования else! То есть идёт работа только с одним путём, а другой путь остаётся местом загадок (и багов!).
Тут на помощь приходит Lodash (лучшее, написанное когда-либо на javascript) с его замечательной функцией get. Её первым аргументом является объект, над которым вы работаете, вторым – путь к дочерним атрибутам, которые вы хотите получить, и третьим является значение по умолчанию в случае с undefined.
Два преимущества использования всего одной функции!
8. Используйте тернарные операторы
Кто-то может поспорить насчёт их читабельности, но если правильно извлекать функции, они станут превосходным инструментом. Они также заставят Вас сотрудничать с else case. Плюс, они не позволяют содержать в себе больше кода.
Чем меньше ваш код похож на смертельную пирамиду, тем лучше.
9. Никаких больше for loops, только map, reduce и filter
Мы, наконец-то, подошли тут к теме функционального программирования, так как эти методы являются основой этого стиля. Хоть названия или теории не особо известны, они действительно помогут избежать тяжело читаемого императивного стиля для выражений for.
Эти методы сейчас уже встроены в большинство браузеров, так что используйте их! Но если вам всё же нужна совместимость, можно использовать lodash аналоги.
Итак, когда их использовать?
Выражение for, имеющее дело со всеми точками входа – это map
for + if , вероятно, filter
sum или accumulation - это просто reduce
С помощью сочетания этих методов вы можете сделать много работы в хорошей и краткой форме.
10. Читайте исходники
Если документации недостаточно - читайте исходники! Это поможет Вам узнать, как их использовать и даст неплохое представление об их качестве.
Плюс, некоторые библиотеки имеют исходники, встроенные в их документацию. Так с ними даже быстрее можно ознакомиться. С нашей IDE можно часто обращаться к источнику с помощью ctrl + clic на имя метода.
Это отличный способ убрать магию и набраться вдохновения для собственного кода!
В заключение хотелось бы сказать, что это те принципы, которые помогают лично мне. Жаль, что я не знал их раньше, например, в школе… Зато ты знаешь их сейчас. И ими можно пользоваться практически в любом контексте. Некоторые из них распространяются не только на javascript, так что пользуйтесь ими где угодно :)
Также хотелось бы обратить ваше внимание на великого Uncle Bob и его сайт . Вам определённо стоит посмотреть эти видео, даже несмотря на то, что они по большей части касаются Java, идеи применимы и в Javascript.
Переведено с источника.
Введення в розробку програм під iOS. Частина 7
Автор: Volodymyr Bozhek
Здравствуйте, дорогие читатели.
В этом уроке мы:
выполним рефакторинг проекта “Warehouse” под “iOS”. Создадим удобную структуру расположения модулей в проекте.
научимся пользоваться библиотекой “Alamofire”.
научимся сохранять объекты в настройки телефона и извлекать их.
реализуем функциональность для работы со всеми сервисами, созданными в данном уроке.
Откройте проект “Warehouse” под iOS, который мы делали на протяжении всех уроков.
Запросы на сервер можно отправлять синхронно и асинхронно. Основное требование Apple, чтобы приложение не зависало и большие операции выполнялись в фоновом режиме.
Представим ситуацию: у нас мобильный интернет “GPRS EDGE”, скорость соединения около 54 кб/сек. Если отправлять запрос на получение данных на сервер синхронно, мы блокируем работу приложения и пользователь вынужден ждать. Наша задача - дать пользователю выбор, ждать или нет. Поэтому лучше всего отправлять такой запрос асинхронно.
На сегодняшний день существует такая библиотека “Alamofire”, где собраны лучшие практики асинхронного программирования и все оптимизировано за нас.
Откройте браузер и перейдите по адресу: “https://github.com/Alamofire/Alamofire”. На сайте нажмите кнопку “Clone of download” и в появившемся окне нажмите “Download Zip”.
Когда скачается архив, распакуйте его.
Выделите файл “Alamofire.xcodeproj” и папку “Source” и скопируйте их в папку проекта “Warehouse”.
Перейдите в проект “Warehouse”.
В панели навигации выполните контекстное меню по папке “Warehouse” и в контекстном меню выберите “Add files to 'Warehouse'...”. В открывшемся диалоговом окне выбора файлов выберите файл “Alamofire.xcodeproj”.
Выполните в меню “Product -> Build”, чтобы собрать проект.
Затем выделите в панели навигации папку “Warehouse”, в области содержимого откроются свойства проекта. Откройте вкладку “General”, пролистайте область содержимого в самый низ.
Установите свойство “Embedded binaries”, нажмите плюсик. В появившемся диалоговом окне, выберите “Alamofire.Framework.iOS” и нажмите кнопку “Add”.
Результат должен получиться таким.
Выполните в меню “Product -> Build”, чтобы собрать проект.
Итак, что мы только что сделали. Мы подключили исходники библиотеки “Alamofire” в проект “Warehouse”. Можно было это сделать и отдельным проектом, но так проще для восприятия. Затем мы подключили сборку “Alamofire.framework.iOS” в приложение “Warehouse” для возможности обращения к классам данной библиотеки из нашего проекта.
Теперь нам надо создать модели данных, в которые мы будем сохранять JSON объекты, полученные с сервера. Также необходимо предусмотреть удобство сохранения и извлечения данных, поскольку запросы будут асинхронными и просто вернуть нужный экземпляр из метода будет проблематично.
Именно поэтому мы поступим следующим образом.
Отправляем запрос на сервер асинхронно. В метод отправки добавляем callback метод, который вызовется после того, как модель была успешно сохранена в настройки телефона.
Ждем ответа. Когда ответ пришел, десериализуем объект JSON в нужную модель данных, объявленную в приложении.
Сохраняем заполненную модель в настройки телефона.
В контроллере, из которого был отправлен запрос, в callback методе извлекаем модель из настроек телефона и инициализируем данными элементы управления.
Создайте следующую структуру папок в панели навигации.
В папку “Warehouse” были добавлены папки “Controllers”, “Protocols”, “Models”, “Services”.
В папку “Controllers” были добавлены папки “Users”, “Registration”, “Authorization”, “Supplies”.
В папке “Controllers” будут храниться модули контроллеров.
В папке “Protocols” будут храниться модули протоколов.
В папке “Models” будут храниться модули моделей данных.
В папке “Services” будут храниться модули обращения к REST сервисам.
Сейчас нам необходимо провести некоторую подготовку, перед тем как начать реализовывать приложение. Пока, давайте, добавим нужные модули. Сам по себе добавленный модуль ничего не делает.
Перетащите в папку “Controllers / Supplies” модули “SuppliesViewController.swift”, “ProductViewController.swift”.
Перетащите в папку “Controllers / Authorization” модуль “ViewController.swift”.
Добавьте в папку “Controllers / Registration” модуль “RegistrationViewController.swift”.
Добавьте в папку “Controllers / Supplies” модуль “ImageCollectionViewController.swift”.
Добавьте в папку “Controllers / Users” модули “UsersViewController.swift”, “UserItemViewController.swift”.
Добавьте в папку “Protocols” модуль “SelectedImageProtocol.swift”.
Добавьте в папку “Models” модули “ProductModel.swift”, “UserModel.swift”.
Добавьте в папку “Services” модули “UserData.swift”, “ProductData.swift”, “Services.swift”, “AuthorizationService.swift”, “ProductService.swift”, “UserService.swift”.
У вас должна получиться следующая структура.
Как видите, проект стал больше. Он станет еще больше, как только мы заполним добавленные модули.
Откройте модуль “Models / UserModel.swift”. Заполните его, как показано ниже.
В этом модуле мы создаем модель пользователя, в которую будем десериализовывать JSON объект пользователя, полученный от сервера.
В классе “UserModel” мы добавляем поля модели “_id”, “userName”, “userPwd”, “userDesc”, которые декларировали при объявлении схемы базы данных “Mongo DB” на сервере.
На 9 строке мы подключаем пространство имен “Foundation”.
На 11 строке мы объявляем класс с именем “UserModel”, который наследует класс “NSObject”, являющийся базовым классом для всех классов в iOS платформе. Наследуемся от протокола “NSCoding”, данный протокол необходимо реализовать, чтобы объект можно было сохранять в настройках телефона и извлекать оттуда.
Рассмотрим протокол “NSCoding”.
Протокол содержит метод “encode” и инициализатор.
Экземпляр класса “NSCoder” позволяет кодировать и раскодировать свойства класса, значения которых могут сохраняться в хранилище настроек телефона.
В методе “encode” данные извлекаются из свойств и кодируются в формат, нужный для сохранения в настройки телефона.
В инициализаторе данные извлекаются и раскодируются из настроек телефона, затем сохраняются в нужные свойства класса.
Вот так это работает.
Теперь вернемся и рассмотрим дальше модуль “UserModel.swift”.
На 12 строке мы объявляем поле “_id” типа “String” и инициализируем его значением по умолчанию, пустая строка.
На 13 строке мы объявляем поле “userName” типа “String” и инициализируем его значением по умолчанию, пустая строка.
На 14 строке мы объявляем поле “userPwd” типа “String” и инициализируем его значением по умолчанию, пустая строка.
На 15 строке мы объявляем поле “userDesc” типа “String” и инициализируем его значением по умолчанию, пустая строка.
На 17 строке мы переопределяем инициализатор по умолчанию для класса “NSObject”, тем самым мы говорим, что создание объекта без передачи аргументов в инициализатор будет возможно.
На 18 строке мы вызываем базовый инициализатор из класса “NSObject”.
На 21 строке мы объявляем параметризированный инициализатор. Данный инициализатор инициализирует поля класса “_id”, “userName”, “userPwd”, “userDesc” значениями, переданными в аргументы инициализатора.
На 31 строке мы реализуем конструктор протокола “NSCoding”. Ключевое слово “required” обозначает, что вызов этого инициализатора обязателен в первую очередь. Ключевое слово “convenience” гарантирует то, что после вызова этого инициализатора будут вызваны остальные инициализаторы классов, связанных с этим классом по цепочке вверх.
На 32 строке мы раскодируем из настроек телефона значение свойства “_id” путем вызова на экземпляре “aDecoder” типа “NSCoder” метода “decodeObject”, аргумент “forKey” которого принимает название поля/свойства, которое было сохранено в настройки телефона.
Этот метод возвращает значение “Any?”, т.е. неопределенный тип (аналог в C# - это Object, в Visual Basic - это Variant). Нам необходимо это значение вручную привести к нужному типу поля.
В настройках телефона содержится большой файл, который имеет древовидную структуру словаря ключ и значение.
Чтобы привести к нужному значению, мы используем конструкцию приведения к типу “as”. Причем, мы можем управлять этой конструкцией.
Например, нам надо привести тип “Any?” к типу “String”. Для этого мы используем конструкцию “as!”.
Если же нам надо привести к типу “String?” (nullable тип), тогда мы используем конструкцию “as?”. Зачем мы это делаем.
Настройки телефона разбиваются на разные файлы, для каждого приложения используется свой файл с настройками.
Когда приложения устанавливаются на macOS или iOS платформу, они устанавливаются в виде папки и имеют тип “Bundle”.
Apple довольно кардинально подошла к этому вопросу, она сделала так, что все настройки для каждого приложения хранятся внутри “Bundle” данного приложения. И когда приложение удаляется, удаляется “Bundle” со всеми настройками с диска операционной системы и не остается никаких следов после удаления.
Чего не скажешь о таких платформах, как Windows и Android, которые засоряют все пространство на диске операционной системы вокруг папки, в которую было установлено приложение, и выше. И когда приложение удаляешь, есть риск, что после этого будет необходимо еще и переустановить операционную систему.
Отчасти именно из-за этого подхода техника Apple пользуется такой популярностью и их устройства выигрывают по отказоустойчивости программного обеспечения по сравнению с конкурентами.
Если приложение обновляется, то файл настроек остается старый. Чтобы обновить его, надо выполнить запись в него, тогда старые конструкции удалятся, а новые добавятся. Представим себе ситуацию, сейчас в нашей модели “UserModel” всего 4 поля. Мы сохранили эту модель в файл настроек телефона. Отправили в магазин, пользователи скачали, установили приложение.
Вышла новая версия приложения, в которой мы добавили новое поле в эту модель с именем “userRole” типа “String”.
Разумеется, первая операция, которая будет выполнена как обычно - это запрос данных из настроек телефона, но для поля “userRole” установлено значение “nil” (аналог в C# null) и произойдет ошибка и креш приложения, так как мы не обработали эту ситуацию, а пытаемся через метод “decodeObject” получить значение этого поля и еще и явно привести его к типу “String” через, например, оператор “as!”.
Но в поле “userRole” - значение “nil” и оно не приведется к типу “String” через конструкцию “as!”, но может привестись без ошибок к типу “String?” через “as?”.
Надеюсь, я прояснил понятно, зачем нужна данная проверка. Продолжим.
На 32 строке мы проверяем, доступно ли нам значение поля “_id”. Чтобы проверить, равно ли возвращаемое значение “nil”, можно было бы использовать такую конструкцию: “aDecoder.decodeObject(..) == nil”, но такая конструкция не слишком информативна.
Поэтому мы используем конструкцию “(aDecoder.decodeObject(..) as? String) == nil”. Далее, если данная конструкция возвращает значение “true”, тогда мы через тернарный оператор присваиваем константе “_id” значение по умолчанию пустая строка, иначе присваиваем реальное значение поля “_id” из настроек телефона.
С 33 по 35 строку мы выполняем те же операции проверок для полей “userName”, “userPwd”, “userDesc”.
На 36 строке мы вызываем параметризированный конструктор и инициализируем его аргументы объявленными ранее константами.
На 47 строке объявлен вспомогательный метод “Populate”, который переносит данные из экземпляра “dictionary” типа “NSDictionary” в поля класса “UserModel”. Этот метод мы будем использовать, когда будем создавать запросы к серверу и получать ответы. В ответе содержится словарь типа “NSDictionary”, в котором находятся свойства с теми же именами, что и поля нашего класса.
С 48 по 51 строку мы инициализируем поля класса “UserModel” значениями из экземпляра “dictionary” c теми же проверками, что мы рассматривали выше.
На 53 строке объявлен вспомогательный метод “PopulateArray”, который переносит данные из экземпляра “array” типа “NSArray” в массив объектов типа “UserModel”. Этот метод мы будем использовать, когда в ответе от сервера придет массив JSON объектов типа “User”, чтобы сконвертировать массив типа “[NSDictionary]” в массив типа “[UserModel]”.
На 55 строке мы объявляем пустой массив типа “[UserModel]” c именем “result”.
На 56 строке мы выполняем цикл “foreach” по элементам массива “array”.
На 58 строке мы создаем новый экземпляр типа “UserModel” с именем “newItem”.
На 59 строке мы проверяем, содержит ли элемент массива значение “nil”.
На 60 строке мы вызываем на экземпляре “newItem” метод “Populate”, который перенесет данные из словаря типа “NSDictionary” в поля экземпляра “newItem”.
На 62 строке мы обращаемся к экземпляру “result” и вызываем у него метод “append”, чтобы добавить новый элемент в массив, и добавляем проинициализированный выше экземпляр “newItem”.
На 64 строке мы возвращаем сконвертированный массив типа “[UserModel]” из метода “PopulateArray”.
Откройте модуль “Models / ProductModel.swift”, заполните его в соответствии с содержимым ниже.
В этом модуле мы создаем модель пользователя, в которую будем десериализовывать JSON объект пользователя, полученный от сервера.
В классе “UserModel” мы добавляем поля модели “_id”, “userName”, “userPwd”, “userDesc”, которые декларировали при объявлении схемы базы данных “Mongo DB” на сервере.
На 9 строке мы подключаем пространство имен “Foundation”.
На 11 строке мы объявляем класс с именем “UserModel”, который наследует класс “NSObject”, являющийся базовым классом для всех классов в iOS платформе. Наследуемся от протокола “NSCoding”, данный протокол необходимо реализовать, чтобы объект можно было сохранять в настройках телефона и извлекать оттуда.
Рассмотрим протокол “NSCoding”.
Данный модуль не нуждается в объяснении, поскольку он по образу и подобию такой же, как и модуль “UserModel.swift”, с разницей лишь в том, что он построен на модели “Product” и содержит соответствующие поля.
Итак, модели данных мы создали, теперь мы сможем с уверенностью сохранять результаты ответа от сервера в нормальном виде и потом использовать их при инициализации элементов управления в соответствующих представлениях :)
Теперь приступаем к реализации классов для отправки запросов на сервер и сохранения/загрузки полученных данных в настройки телефона.
Откройте модуль “Services / Services.swift”, заполните его в соответствии с содержимым ниже.
На 11 строке объявлен класс с именем “Services”. Данный класс будет содержать вспомогательные свойства и методы, которые мы будем часто использовать при работе с ответом от сервера.
На 12 строке объявлено статическое свойство “host” типа “String” и мы ограничили его функциональность только одним аксессором доступа “get”. Т.е. значение свойства получить можно, но изменить нельзя. В данном свойстве содержится адрес, по которому доступен сервер.
В прошлом уроке, когда мы делали сервер, мы использовали адрес “http://localhost:3000” , внутри приложения клиента имеется свой “localhost”, именно поэтому мы используем явный IP адрес “127.0.0.1”, чтобы запрос шел именно на сервер, а не внутрь приложения.
На 18 строке объявлен статический метод “ejectJsonArray”, который принимает аргумент “data” типа “NSData?” и возвращает массив типа “NSArray?”. Данный метод конвертирует экземпляр класса “NSData” в экземпляр класса “NSArray”. В экземпляре “data” будет содержаться массив JSON объектов, полученных от сервера.
На 19 строке объявлена переменная “json” типа “NSArray?” и инициализировано значение по умолчанию “nil”.
На 20 строке мы используем конструкцию “do .. try .. catch” (аналог в C# - “try .. catch”). Символ “_” в блоке “catch” на месте аргумента используется потому, что мы не будем использовать этот аргумент в блоке “catch”.
В случае возникновения исключения мы не будем завершать аварийно приложение, а просто вернем значение “nil” по умолчанию, которое будет говорить о том, что конвертация не удалась, поскольку в NSData не содержится JSON объект.
Аналог JSON объекта в Swift - это класс “NSDictionary”.
На 21 строке мы правым операндом обращаемся к классу “JSONSerialization” и вызываем от его экземпляра статический метод “jsonObject”, который первым аргументом принимает данные типа “Data” для конвертации, вторым аргументом принимает опции конвертации.
Метод “jsonObject” возвращает экземпляр типа “Any”. Далее мы приводим это значение к нужному нам типу “NSArray?”, если приведение было проведено не успешно, будет возвращено значение “nil”.
Результат конвертации присваивается объявленной выше переменной “json”. Обратите внимание на ключевое слово “try” перед конструкцией “JSONSerialization.jsonObject(..)”, использование этого ключевого слова является обязательным, так как метод “jsonObject” имеет в своей сигнатуре ключевое слово “throws”, это означает, что данный метод может генерировать исключения и их необходимо обрабатывать.
На 23 строке в случае исключения вызванного методом “jsonObject” возвращается значение “nil”.
На 25 строке в случае успеха операции возвращается экземпляр типа “NSArray?”.
На 28 строке объвлен метод “ejectJsonDictionary” с той же сигнатурой, что и метод “ejectJsonArray”, но с разницей в возвращаемом значении.
В этом методе возвращается экземпляр типа “NSDictionary?”. Метод подразумевает, что в экземпляре “data” типа “NSData?” содержится единичный JSON объект и пытается его сконвертировать в тип “NSDictionary” , являющийся аналогом JSON объектов в Swift. Реализацию метода смысла описывать не вижу, она такая же, как и в методе “ejectJsonArray”.
Реализуем сохранение моделей данных “UserModel” и “ProductModel” в настройки телефона.
Откройте модуль “Services / UserData.swift”, заполните его в соответствии с содержимым ниже.
Модуль большой, поэтому будем разбирать его, разбив на две части по функциональности.
В первой его части будут описаны методы сохранения / извлечения единичного экземпляра типа “UserModel” и экземпляра типа массив “[UserModel]”.
Во второй его части будут описаны вспомогательные методы для обработчиков ошибок ответа от сервера и сохранения данных в настройки телефона.
Данные методы были созданы для того, чтобы не копипастить один и тот же код много раз, а стандартизировать и сделать его повторно используемым.
На 9 строке подключено пространство имен “UIKit”, необходимое для классов “UserDefaults”, “NSKeyedArchiver”, “NSKeyedUnarchiver”. В пространстве имен уже содержится подключенное пространство имен “Foundation”, поэтому нет смысла его тоже подключать для классов “NSArray”, “NSDictionary”, “NSData”.
На 10 строке подключено пространство имен “Alamofire”, необходимое для класса “DataResponse”.
На 12 строке объявлен класс с именем “UserData”.
На 13 строке объявлен метод “saveUserModel”, который принимает аргумент “userModel” типа “UserModel”. Метод будет сохранять поля модели “UserModel” в настройки телефона.
На 14 строке правым операндом мы обращаемся от экземпляра “UserDefaults” к его статическому свойству “standard”, это свойство является источником данных по отношению к файлу настроек телефона и содержит необходимые методы для сохранения / извлечения данных.
На 15 строке правым операндом мы обращаемся к экземпляру “NSKeyedArchiver” и вызываем статический метод “archivedData”. Этот метод принимает один аргумент “withRootObject” типа “Any” и возвращает экземпляр типа “Data”. Метод упаковывает экземпляр типа “UserModel” в экземпляр типа “Data” (аналог NSData) и возвращает его.
На 16 строке мы от экземпляра “userDefaults” вызываем метод “set”, который принимает два аргумента. Первый аргумент “_” типа “Any?” принимает экземпляр, который необходимо сохранить в настройках телефона. Второй аргумент “forKey” типа “String” необходим, чтобы задать название ключа в словаре настроек телефона. По этому ключу будет произведено сохранение экземпляра “UserModel”.
На 17 строке мы обращаемся к экземпляру “userDefaults”, вызываем от него метод “synchronize”. Данный метод выполняет сохранение экземпляра модели “UserModel” в настройки телефона (аналог в C#, например, 'using(StreamWriter sw = File.CreateText(“test.txt”)) { sw.Write(“some text”); sw.Flush(); }', из этого примера метод “Write” аналогичен методу “set”, а метод “Flush” аналогичен методу “synchronize”).
На 20 строке мы объявили статический метод “getUserModel”, который не принимает аргументов и возвращает экземпляр типа “UserModel”. В этом методе мы излекаем модель “UserModel” из файла настроек телефона по ключу, указанному в предыдущем методе при сохранении этой модели.
На 21 строке мы получаем экземпляр источника данных настроек телефона.
На 22 строке мы проверяем, если модель “UserModel” ранее не сохранялась в настройки телефона, тогда необходимо создать пустую модель по умолчанию.
Вызываем на экземпляре “userDefaults” метод “object”, который принимает аргумент “forKey” типа “String” и возвращает значение типа “Any?”. В качестве аргумента мы передаем ключ, под которым сохраняется данная модель в настройках телефона.
Если значение было найдено в словаре, будет возвращен экземпля , который надо будет привести у нужному типу.
Если значение не было найдено, будет возвращено значение “nil”.
На 23 строке мы создаем пустой экземпляр типа “UserModel”.
На 24 строке мы возвращаем этот экземпляр из метода.
На 26 строке код будет выполнен при наличии записи по ключу в словаре. Правым операндом мы обращаемся к экземпляру “userDefaults”, вызываем метод “object” и передаем в аргумент “forKey” ключ, по которому надо извлечь значение. Полученное значение приводим к типу “NSData”.
На 27 строке мы обращаемся к экземпляру “NSKeyedUnarchiver” и вызываем от него статический метод “unarchiveObject”, который принимает аргумент “with” типа “Data” и возвращает значение типа “Any”. Метод конвертирует экземпляр типа “Data” в экземпляр типа “Any”. Возращаемое значение метода мы явно приводим к типу “UserModel”.
На 28 строке мы возвращаем из метода полученный из словаря экземпляр типа “UserModel”.
На 31 строке объявлен метод “saveListOfUsersModel”, который принимает аргумент “listOfUsersModel” типа “[UserModel]” и ничего не возвращает. Метод сохраняет массив “[UserModel]” в файл настроек телефона. Описывать данный метод не имеет смысла, его работа аналогична методу “saveUserModel”.
На 38 строке объявлен метод “getListOfUsersModel”, который не принимает аргументов и возвращает экземпляр типа массив “[UserModel]”. Метод извлекает из настроек телефона массив типа “[UserModel]” по ключу, указанному в методе “saveListOfUsersModel”. Описывать данный метод не имеет смысла, его работа аналогична методу “getUserModel”.
Откройте модуль “ProductData.swift”, заполните его в соответствии с содержимым ниже.
В первой части описано сохранение / извлечение моделей типа “ProductModel”, “[ProductModel]” в настройки телефона. Описывать код не имеет смысла, его работа точно такая же, как и в модуле “UserData.swift”.
Во второй части описаны вспомогательные методы для обработки запросов от сервера и сохранения данных. Описывать код не имеет смысла, его работа точно такая же, как и в модуле “UserData.swift”.
Теперь, наконец то, мы можем реализовать первый класс для работы с сервисом авторизации пользователя и разобрать работу с библиотекой “Alamofire”.
Откройте модуль “Services / AuthorizationService.swift”, заполните его в соответствии с содержимым ниже.
На 12 строке объявлен класс с именем “AuthorizationService”.
На 13 строке объявлен метод “login”, который принимает три аргумента и ничего не возвращает.
Первый аргумент “userName” типа “String” - это имя пользователя (логин).
Второй аргумент “userPwd” типа “String” - это пароль пользователя.
Третий аргумент - это “callback” метод, который принимает аргумент типа “Bool” и ничего не возвращает.
Метод с такой сигнатурой, переданный в третий аргумент, будет вызван по завершению обработки ответа от сервера. В случае наличия ошибок в аргумент этого метода будет передано значение “false”. В случае успешно проведенной операции - значение “true”.
Да, можно было сделать этот аргумент другим типом, например, отдельным классом ошибок, в который можно было сохранять подробно, что за ошибка произошла.
Но это учебный пример, он итак очень большой. Я решил не усложнять этим жизнь ни себе, ни вам :)
На 14 строке правым операндом мы вызываем метод “request” из библиотеки “Alamofire”.
Метод принимает 5 аргументов и возвращает значение типа “DataRequest”.
Данный метод используется для отправки HTTP/HTTPS запросов на сервер.
Первый аргумент “_” типа “URLConvertible” принимает адрес, по которому необходимо отправить запрос. Мы его инициализируем значением “\(Services.host)/auth”, которое после подстановки свойства “host” будет выглядеть вот так: “http://127.0.0.1:3000/auth”.
Второй аргумент “method” типа “HTTPMethod” принимает HTTP глагол. Тип “HTTPMethod” является перечислением и может принимать следующие значения.
Мы инициализируем данный аргумент значением “.post” (это сокращенная запись, полная запись “HTTPMethod.post”)
Третий аргумент “parameters” типа “Parameters?”. Принимает словарь, ключ - значение, мы его заполняем теми же данными, что отправляли в прошлом уроке через утилиту “Postman”. Конкретно, мы передаем значение имени пользователя и его пароль.
Четвертый аргумент “encoding” типа “ParameterEncoding”. Этим параметром задается заголовок запроса “Content-Type”, т.е. указывается тип данных, который будет отправлен на сервер, сами данные задаются в третьем аргументе “parameters”. Мы инициализируем аргумент значением “JSONEncoding.default”, что аналогично записи “application/json”. Тип “ParameterEncoding” является протоколом и имеет следующие реализации себя в классах “URLEncoding”, “JSONEncoding”, “PropertyListEncoding”. Про эти классы вы можете почитать в официальной документации на сайте “Alamofire”.
Пятый аргумент “headers” типа “HTTPHeaders?” имеет значение по умолчанию “nil”, в нашем вызове метода он не используется. Данный аргумент задается, если вы желаете отправить в заголовках запроса на сервер какую- либо информацию, например, “cookie”. Если у вас сервер написан на Web API и вы используете для авторизации OWin , с настройкой надо использовать “cookie” как ключ авторизации пользователя. Тогда при отправке запросов вам будет необходимо заполнять этот аргумент. Пример его заполнения может выглядеть вот так:
Этот пример взят из моего приложения “Smart Payment”, написанного на Swift 2.2 c минимальной версией iOS 8.3 библиотекой “Alamofire” версии 2. Чтобы этот пример работал на Swift 3, надо заменить значение параметра “encoding” на “JSONEncoding.default”. Этот пример не относится к нашему приложению и его переписывать не нужно.
На 16 строке мы вызываем от экземпляра “r” типа “DataRequest” метод “responseJSON”. Этот метод выполняет запрос на сервер и содержит три аргумента.
Первый аргумент “queue” типа “DispatchQueue?” по умолчанию содержит значение “nil”. Используется при переопределении потока выполнения запроса.
Второй аргумент “options” типа “JSONSerialization.ReadingOptions” по умолчанию содержит значение “.allowFragments”. Используется для задания опция отправки запроса. Тип “ReadingOptions” является структурой и имеет такое объявление.
Третий аргумент “completionHandler” типа делегат “@escaping (DataResponse) -> Void”. Данная сигнатура принимает один аргумент типа “DataResponse” и ничего не возвращает. В этом аргументе содержится ответ от сервера. Сам метод вызывается после запроса, когда сервер отправил ответ на клиент.
Обратите внимание, на 16 строке, когда мы вызываем метод “responseJSON”, у нас нет круглых скобок после метода, а идут сразу фигурные скобки, это называется “closure” подход. В фигурных скобках мы объявляем лямбда метод с сигнатурой, соответствующей третьему аргументу метода “responseJSON”.
Запись “response in” означает следующее: “response” - это аргумент лямбда метода, а само тело метода начинается после ключевого слова “in”. Аргумент “response” имеет тип “DataResponse”.
На 17 строке мы проверяем, если ответ пришел с ошибкой, то это означает, что данных нет и пришло пустое значение типа “nil”. Мы обращаемся к экземпляру “response” и вызываем свойство “result” типа “Result” и от свойства “result” вызываем свойство “value” типа “Value?”. Если в свойстве “value” пришло пустое значение, значит запрос не был выполнен, возможно, по причине недоступности сервера или отсутствия подключения к интернету.
На 18 строке мы вызываем “callback” метод “completion” со значением “false”.
На 21 строке, в случае если проблем с подключением к серверу не возникло, мы правым операндом вызываем от экземпляра “Services” метод “ejectJsonDictionary”, который ранее уже подробно рассматривали. В аргумент “data” мы передаем значение свойства “data”, вызванного от экземпляра “response”. Свойство “data” имеет тип “Data?”. Левому операнду “json” присваивается экземпляр “NSDictionary”, в котором содержится JSON объект пользователя, прошедшего авторизацию, который был отправлен сервером на клиент.
На 22 строке мы проверяем, если пришел JSON объект с ошибкой, тогда возвращаем нужный флаг в “callback” методе “completion”. Помним, что в предыдущем уроке мы создавали JSON объект с ошибкой на сервере, в случае если пользователь ввел неверные данные авторизации, JSON выглядел вот так '{ “Error”: “Authorization error”}'.
У словаря “json” есть возможность получить все ключи, для этого надо вызвать свойство “allKeys”, которое имеет тип “[Any]”. Но, поскольку выполнить поиск строки в массиве объектов нельзя, мы оборачиваем массив объектов в массив типа “Array” и явно приводим его к нужному нам типу массива “[String]”. Мы это делаем, поскольку знаем наверняка, что ключи JSON объекта имеют тип “String”. Затем от полученного экземпляра типа “[String]” мы вызываем метод “contains”, в аргумент которого передает название свойства JSON объекта ошибки, значение “Error”. Если такой JSON объект пришел в ответе, значит пользователь ввел неправильные логин или пароль, или ввел несуществующего пользователя.
На 23 строке мы вызываем “callback” метод “completion” с аргументом “false”.
На 25 строке мы создаем пустой экземпляр “userModel” типа “UserModel”.
На 26 строке мы вызываем на экземпляре “userModel” метод “Populate” в аргумент “dictionary”, передаем экземпляр “json”. Метод “Populate” перенесет данные из экземпляра “json” типа “NSDictionary” в поля экземпляра “userModel”.
На 27 строке мы обращаемся к экземпляру “UserData” и вызываем статический метод “saveUserModel”, чтобы сохранить данные экземпляра “userModel” в настройки телефона. В аргумент “userModel” мы передаем экземпляр “userModel”.
На 28 строке мы вызываем “callback” метод “completion” и передаем в него результат операции “true”.
Позже в контроллере, где мы будем вызывать метод “login”, будет передан “callback” метод “completion”, объявленный в этом контроллере. Тем самым решается проблема ожидания ответа от сервера в контроллере, так как есть “callback” метод. Внутри этого метода мы проверим результат операции и затем обратимся к экземпляру “UserData” и вызовем метод “getUserModel”, который вернет нам экземпляр “UserModel”, с которым мы сможем работать на стороне контроллера.
Откройте модуль “Services / UserService.swift”, заполните его, как показано ниже.
На 12 строке объявлен класс “UserService”.
На 13 строке объявлен метод “get”, который принимает два аргумента и ничего не возвращает.
Первый аргумент “id” типа “String?” принимает идентификатор пользователя “_id”. Если передать в аргумент значение “nil”, будет возвращен весь список пользователей, если передать конкретный идентификатор, будет возвращен конкретный пользователь.
Второй аргумент “completion” типа делегат “(Bool) -> Void” используется для получения сигнала, что ответ был получен и основные операции были выполнены.
На 29 строке объявлен метод “create”, который принимает 4 аргумента и ничего не возвращает. Метод отправляет запрос на создание пользователя на сервер.
Первые три аргумента “userName”, “userPwd”, “userDesc” имеют тип “String” и содержат данные пользователя. Идентификатор пользователя в операции создания не нужен. Так как идентификатор пользователю присваивается на стороне сервера и данный метод выполняет как раз эту операцию.
Четвертый аргумент “completion” типа делегат “(Bool) -> Void” используется для получения сигнала, что ответ был получен и основные операции были выполнены.
На 37 строке объявлен метод “update”, который принимает 5 аргументов и ничего не возвращает. Данный метод отправляет запрос на обновление данных пользователя на сервер.
Первые 4 аргумента “id”, “userName”, “userPwd”, “userDesc” имеют тип “String” и содержат данные пользователя.
Пятый аргумент “completion” типа делегат “(Bool) -> Void” используется для получения сигнала, что ответ был получен и основные операции были выполнены.
На 45 строке мы объявляем метод “delete”, который принимает два аргумента. Этот метод отправляет запрос на удаление пользователя на сервер.
Первый аргумент “id” типа “String?” принимает идентификатор пользователя “_id”.
Второй аргумент “completion” типа делегат “(Bool) -> Void”, используется для получения сигнала, что ответ был получен и основные операции были выполнены.
Откройте модуль “Services / ProductService.swift”, заполните его, как показано ниже
На 12 строке объявлен класс “ProductService”.
На 13 строке объявлен метод “get”, который принимает два аргумента и ничего не возвращает.
Первый аргумент “id” типа “String?” принимает идентификатор товара “_id”. Если передать в аргумент значение “nil”, будет возвращен весь список товаров, если передать конкретный идентификатор, будет возвращен конкретный товар.
Второй аргумент “completion” типа делегат “(Bool) -> Void” используется для получения сигнала, что ответ был получен и основные операции были выполнены.
На 29 строке объявлен метод “create”, который принимает 4 аргумента и ничего не возвращает. Метод отправляет запрос на создание товара на сервер.
Первые три аргумента “productImage”, “productName”, “productDescription” имеют тип “String” и содержат данные товара. Идентификатор товара в операции создания не нужен. Так как идентификатор товару присваивается на стороне сервера и данный метод выполняет как раз эту операцию.
Четвертый аргумент “completion” типа делегат “(Bool) -> Void” используется для получения сигнала, что ответ был получен и основные операции были выполнены.
На 37 строке объявлен метод “update”, который принимает 5 аргументов и ничего не возвращает. Данный метод отправляет запрос на обновление данных товара на сервер.
Первые 4 аргумента “id”, “productImage”, “productName”, “productDescription” имеют тип “String” и содержат данные пользователя.
Пятый аргумент “completion” типа делегат “(Bool) -> Void” используется для получения сигнала, что ответ был получен и основные операции были выполнены.
На 45 строке мы объявляем метод “delete”, который принимает два аргумента. Этот метод отправляет запрос на удаление товара на сервер.
Первый аргумент “id” типа “String?” принимает идентификатор товара “_id”.
Второй аргумент “completion” типа делегат “(Bool) -> Void” используется для получения сигнала, что ответ был получен и основные операции были выполнены.
Заметьте, адреса запросов, используемых нами при отправке на сервер, совпадают с теми, что мы использовали в прошлом уроке в утилите “Postman”.
На этом урок завершен.
На следующем уроке мы продолжим разработку клиента, создадим контроллеры и представления для редактирования пользователей, подключим работу сервисов к странице входа в систему, создадим форму регистрации пользователя.
Введення в розробку програм під iOS. Частина 4
Автор: Volodymyr Bozhek
Здравствуйте, дорогие читатели.
В этом уроке мы научимся:
скрывать клавиатуру мобильного устройства для полей “Text Field”, “Text View”;
добавлять различные типы клавиатур цифровая, e-mail, URL;
добавлять панель инструментов на клавиатуру мобильного устройства;
добавим панель поиска в список товаров;
добавим предварительный просмотр на ячейки списка товаров с использованием аппаратной технологии 3D Touch.
Откройте проект Warehouse.
В панели навигатора откройте модуль “ViewController.swift”, нам необходимо унаследоваться от протокола “UITextFieldDelegate”:
Теперь реализуем этот протокол:
Разберем код построчно.
На 43 строке мы реализовали метод “textFieldShouldReturn” протокола “UITextFieldDelegate”. Метод вызывается, когда вы на клавиатуре мобильного устройства нажимаете кнопку “Return” (Done, Next).
Метод принимает один аргумент, который содержит экземпляр текстового поля, для которого была вызвана клавиатура. Возвращаемое значение данного метода говорит о том, скрывать клавиатуру или нет. Мы возвращаем значение “true”, означающее, что мы хотим скрывать клавиатуру.
С 44 по 51 строку идет поиск активного в данный момент текстового поля, куда пользователь установил курсор. Данный код мы добавили, чтобы сделать следующую функциональность. Пользователь ставит курсор в поле “Имя пользователя”, вводит имя пользователя. Затем на клавиатуре нажимает кнопку “Next”, курсор автоматически попадает на поле пароль. После того, как пользователь ввел пароль, он нажимает кнопку “Done” и клавиатура пропадает.
Чтобы поставить курсор в текстовое поле, необходимо на экземпляре этого текстового поля вызвать метод “becomeFirstResponder”.
Чтобы убрать курсор с текстового поля, необходимо на экземпляре текстового поля вызвать метод “resignFirstResponder”.
На 55 строке мы переопредили метод “touchesBegan”. Данный метод объявлен в классе “UIResponder”, класс “UIViewController” наследуется от этого класса.
Метод “touchesBegan” вызывается, когда вы нажимаете в любую свободную область экрана, находящуюся вне редактируемого текстового поля.
На 56 строке мы обращаемся к внутреннему свойству “view”, которое содержит экземпляр представления, подвязанного к контроллеру. И на нем вызываем метод “endEditing” со значение аргумента “true”.
Данный метод посылает представлению событие о том, что необходимо завершить редактирование элементов управления, которые на нем расположены.
Но это еще не все. Теперь необходимо сообщить текстовым полям, что мы реализовали для них соответствующий протокол “UITextFieldDelegate” и хотим проинициализировать у них свойство “delegate”.
Обновите код в методе “viewDidLoad”:
На 30 и 31 строке мы проинициализировали свойство “delegate” для текстовых полей “Имя пользователя” и “Пароль пользователя”. Теперь эти поля знают, откуда им надо вызывать реализацию метода “textFieldShouldReturn”.
Откройте модуль “Main.storyboard”, найдите и выделите представление “View Controller”. На этом представлении выделите текстовое поле “Имя пользователя”. В панели свойств откройте вкладку “Show the Attributes inspector”. Найдите свойство “Return key” и установите в него значение “Next”.
Затем выделите текстовое поле “Пароль пользователя” и установите для его свойства “Return key” значение “Done”.
Запустите приложение.
Если клавиатура у вас не открылась в симуляторе, выполните в меню симулятора “Hardware -> Keyboard -> Toggle Software Keyboard”.
Теперь давайте разберем, какие типы клавиатур имеются и в каком свойстве они задаются. Потренируемся пока на текстовом поле “Имя пользователя”. Выделите это текстовое поле в дизайнере и в панели свойств на вкладе “Show the Attributes inspector” найдите свойство “Keyboard Type”, в этом свойстве задается тип вызываемой клавиатуры для текстового поля.
Часто используемые виды клавиатур:
Default – клавиатура по умолчанию, содержит в себе все раскладки.
Numbers and punctuation – клавиатура содержит цифры и знаки пунктуации.
URL – клавиатура содержит все необходимые символы для быстрого ввода URL адреса.
Number Pad – клавиатура содержит только цифры, без знаков разделения на дробные составляющие.
Phone Pad – телефонная клавиатура.
E-mail Address – клавиатура содержит необходимые символы для быстрого ввода e-mail адреса.
Decimal Pad – клавиатура содержит цифры и знаки разделения на дробные составляющие.
Теперь добавим функциональность закрытия клавиатуры для представления редактирования продукта. Откройте модуль “ProductViewController.swift”. Добавьте наследование от двух протоколов “UITextFieldDelegate”, “UITextViewDelegate”, для класса “ProductViewController”:
Реализуем эти протоколы:
Методы на 58 строке и 69 мы рассматривали уже ранее, не буду повторяться.
На 64 строке мы реализовали метод “textViewDidEndEditing”, данный метод вызывается, когда редактирование многострочного текстового поля было завершено.
Обновим код в методе “viewDidLoad”:
Запустите приложение. Закрытие клавиатуры будет работать только для текстового поля “Название”, для описания работать не будет.
Дело в том что, чтобы скрыть клавиатуру у поля “Text View”, надо добавить дополнительную панель инструментов над клавиатурой и на нее добавить кнопку, которая будет закрывать эту клавиатуру.
Разберем, как это сделать. Обновите код:
Разберем код построчно.
На 37 строке мы вызываем метод “addToolbar”, который добавим ниже. Данный метод принимает аргумент типа “UITextView”, в него мы передаем экземпляр текстового поля, к клавиатуре которого будет привязана панель инструментов с кнопкой закрыть.
На 40 строке мы объявили метод “addToolbar”.
На 41 строке мы создали экземпляр панели инструментов. Чтобы добавить эту панель на клавиатуру, надо проинициализировать свойство “inputAccessoryView” созданной панелью инструментов.
С 42 по 44 строку мы задаем визуальные стили панели инструментов.
На 45 строке мы создаем экземпляр кнопки пробел.
На 46 строке мы создаем экземпляр кнопки “Х Закрыть” и привязываем к нему метод обработчик “donePressed” на нажатие по кнопке.
На 47 строке мы добавляем кнопки на панель инструментов.
На 48 строке говорим, что панель инструментов будет принимать действия пользователя.
На 49 строке мы вызываем метод “sizeToFit”, который растянет панель инструментов по ширине экрана.
На 51 строке инициализируем свойство “delegate” текстового поля.
На 52 строке добавляем панель инструментов на клавиатуру.
Запустите приложение.
Теперь, при нажатии на кнопку “Х Закрыть” на панели инструментов клавиатуры, клавиатура закрывается. Данный код еще удобно использовать для цифровых клавиатур.
Добавим поле поиска товаров в представление списка товаров. Откройте модуль “SuppliesViewController.swift”.
Добавьте наследование от протоколов “UISearchResultsUpdating” и “UISearchBarDelegate”. Обновите код:
Разберем код.
На 27 строке мы добавили свойство “filteredSupplies”, в котором будут содержаться найденные товары через поле поиска.
На 28 строке мы добавили свойство, которое указывает, активно ли сейчас поле поиска или нет.
На 29 строке мы объявили пока еще не инициализированный экземпляр контроллера для поля поиска типа “UISearchController”.
Отлично, теперь обновим методы табличного представления “numberOfRowsInSection” и “cellForRowAt indexPath”:
Разберем код.
На 74 строке мы проверяем, является ли поле поиска в данный момент активным (т.е. мы в данный момент поставили в него курсор).
Тогда на 75 строке мы возвращаем количество товаров из отфильтрованной коллекции.
Иначе на 78 строке мы возвращаем исходный список товаров.
На 84 строке мы изменили получение модели товара. Теперь мы проверяем: если поле поиска в данный момент активно, то возвращаем товар из отфильтрованной коллекции, иначе возвращаем товар из исходной коллекции.
Ошибки с индексом за пределами коллекции у нас не будет, так как выше мы обновили реализацию метода “numberOfRowsInSection”.
Теперь необходимо добавить метод, который будет инициализировать контроллер для поля поиска:
Разберем код этого метода.
На 131 строке мы инициализируем свойство “searchController”, которое объявляли ранее.
На 132 строке мы указываем ссылку на представление, где находятся данные, которые мы будет фильтровать.
На 133 строке мы указываем, доступен ли нам основной контент в ходе поиска данных.
На 134 строке мы задаем текст, который будет отображаться в поле поиска.
На 135 строке мы инициализируем свойство “delegate” поля поиска, тем самым говоря, откуда ему брать реализацию связанных с ним протоколов. Мы указали, что реализация находится в контроллере “SuppliesViewController”.
На 136 строке мы вызываем метод “sizeToFit” на поле поиска, чтобы растянуть панель поиска по ширине экрана.
На 137 строке левым операндом мы обращаемся к свойству “tableHeaderView” экземпляра таблицы и правым операндом инициализируем его нашим полем поиска. Тем самым мы добавляем в заголовок нашей таблицы поле поиска.
Наше приложение на русском языке. А когда поле поиска становится активным, мы видим справа от него кнопку с текстом на английском языке “Cancel”, давайте сразу это исправим, чтобы потом не возращаться к этому:
Разберем построчно код.
На 141 строке мы обращаемся к свойству “searchController”, от него вызываем свойство “searchBar” - это наше поле поиска. И на экземпляре поле поиска вызываем свойство “showsCancelButton”, говорящее о том, отображать кнопку “Cancel” справа от поля поиска или не отображать. Мы говорим, что будем отображать.
На 142 строке мы объявляем переменную типа “UIButton” с именем “cancelButton”.
На 143 строке мы получаем представление, в котором будем производить ниже поиск кнопки с текстом “Cancel” по типу разумеется :)
На 144 строке мы проходимся по иерархии вложенных представлений в поле поиска.
На 145 строке мы проверяем: если представление имеет тип “UINavigationButton”, то это то представление, которое нам надо, это и есть наша кнопка с текстом “Cancel”.
На 146 строке мы инициализируем переменную “cancelButton” экземпляром найденной кнопки.
На 147 строке мы задаем текст кнопки “Отмена”.
Реализуем протокол “UISearchResultsUpdating”:
Разберем код.
На 154 строке мы вызываем метод “searchDisplayControllerWillBeganSearch”, который ранее рассматривали уже, и передаем в аргумент “controller” экземпляр контроллера поиска, который у нас есть в аргументе метода “updateSearchResults”.
На 155 строке мы проверяем, ввел ли пользователь какой -либо текст в поле поиска, если ввел, тогда сохраняем этот текст в переменную “searchString”, если не ввел, тогда выходим из метода “updateSearchResults”.
На 159 строке мы выполняем фильтрацию данных из основного источника данных по тексту, который ввел пользователь в поле поиска. Для этого у коллекции “supplies” вызываем метод “Filter”, в который передаем лямбда метод с одним аргументом типа “ProductModel”, и возвращаемым значением типа Bool (найден или не найден товар).
На 160 строке мы создаем переменную с именем “product” типа “ProductModel” и инициализируем ее экземпляром аргумента “productItem”. Заметьте, лямбда метод будет вызываться столько раз, сколько элементов товара содержит коллекция “supplies”.
На 161 строке мы объявляем переменную, в которой будет содержаться результат сравнения текста поиска с названием или описанием нашего товара.
На 162 строке мы выполняем сравнение текста текущего товара в лямбда методе с текстом поля поиска . Оба текста путем вызова метода “lowercased” переведены в нижний регистр и теперь регистро независимы. Если по названию товара совпадений не было найдено, пытаемся сравнить по описанию товара. Результат сравнения записываем в переменную результата “res”.
На 164 строке возвращаем результат метода “filter”.
На 166 строке запускаем переинициализацию таблицы для отображения отфильтрованных данных и скрытия данных, не попавших под фильтр.
Реализуем протокол “UISearchBarDelegate”:
Разберем код.
На 170 строке мы реализовали метод “searchBarTextDidBeginEditing”, который вызывается, когда пользователь начинает вводить текст в поле поиска. В реализации данного метода мы задаем свойство “shouldShowSearchResults” в значение “true”, тем самым давая понять контроллеру поиска, что поле поиска сейчас активно. Затем мы переинициализируем таблицу.
На 175 строке мы реализовали метод “searchBarCancelButtonClicked”, который вызывается, когда пользователь нажал кнопку “Cancel” или в нашем случае “Отмена”, справа от поля поиска. В реализации мы говорим, что поле поиска теперь больше не активно и переинициализируем таблицу.
На 180 строке мы реализовали метод “searchBarSearchButtonClicked”, который вызывается, когда на клавиатуре, отобразившейся к полю поиска, мы нажали кнопку “Search” (“Поиск”).
В реализации метода мы проверяем: если свойство “shouldShowSearchResults” еще не активно, активируем его и переинициализируем таблицу. Затем скрываем клавиатуру для поля поиска на 185 строке.
Обновите метод “viewDidLoad”:
На 64 строке мы добавили заголовок представления “Продукты”.
На 66 строке мы вызвали метод, который выполняет инициализацию контроллера поиска и добавляет его в наше представление.
Запустите приложение.
Нажмите на поле “Поиск товара”, введите туда, например, букву “Ш”.
Все работает :)
Теперь в этом уроке нам еще осталось добавить предварительный просмотр товара при выполнении на нем функции 3D Touch. Данная функция поддерживается только на устройствах iPhone 6s / 6s Plus / 7 / 7 Plus. В этих телефонах установлен специальный дисплей, который реагирует на силу нажатия на него. Даже если у вас нет подобного девайса это не проблема, так как данную функциональность можно проверить в симуляторе.
Реализуем протокол “UIViewControllerPreviewingDelegate”. Обновите код “SuppliesViewController”:
Теперь обновите метод “viewDidLoad”:
На 67 строке мы обращаемся к свойству контроллера “traitCollection”, в котором содержится свойство “forceTouchCapability”, и проверяем: если данное устройство поддерживает данную функцию (3D Touch), тогда вызываем метод “registerForPreviewing”, в который первым аргументом передаем ссылку на контроллер, для которого надо применить данную функциональность, и экземпляр таблицы, на содержимом которой эта функциональность и будет выполняться.
Добавим реализацию протокола “UIViewControllerPreviewingDelegate”:
Разберем код.
На 192 строке мы реализовали метод “previewingContext”, который возвращает экземпляр представления , которое надо отобразить в предварительном просмотре. Метод принимает два аргумента.
Первый аргумент “previewContext” типа “UIViewControllerPreviewing” принимает экземпляр контроллера предварительного просмотра.
Второй аргумент “location” типа “CGPoint” содержит позицию места, где пользователь выполнил усиленное нажатие по ячейке таблицы.
На 193 строке мы получаем экземпляр “indexPath” путем вызова на таблице метода “indexPathForRow”, аргументом которого мы передаем аргумент “location”.
Данный экземпляр нам необходим, поскольку у него имеется свойство “row” и по значению этого свойства мы сможем получить нужную модель товара.
На 194 строке мы производим поиск контроллера ”ProductViewController” по его “Storyboard ID”. Это представление редактирования товара.
На 195 строке мы передаем идентификатор товара в свойство “id” найденного выше контроллера.
На 196 строке мы передаем в свойство “sourceRect” полную область ячейки, по которой было выполнено “3D Touch”. Благодаря этому данная область будет выделена, когда вы выполните нажатие “3D Touch” в таблице.
На 197 строке возвращаем найденный контроллер “ProductViewController”.
На 199 строке возвращается пустое значение, если пользователь выполнил нажатие “3D Touch” вне области таблицы.
На 202 строке мы реализовали метод “previewingContext” перегруженный, который ничего не возвращает и отображает представление того контроллера, который мы вернули в методе выше.
Запустите приложение.
На этом завершим урок.
На следующем уроке мы рассмотрим создание иконки нашего приложения и разберемся, как пользоваться “Assets”.
Введення в розробку програм під iOS. Частина 3
Автор: Volodymyr Bozhek
Здравствуйте, дорогие читатели.
В этом уроке мы:
создадим форму редактирования товара;
рассмотрим понятие делегата и удобство его использования;
добавим действия редактирования / удаления товара в списке товаров.
Откройте проект Warehouse.
В первую очередь, давайте изменим цвет View входа в систему с “Light Green” на “White”, я явно перестарался с выбором цвета в самом начале :).
В будущих уроках, когда разберем, как пользоваться Assets, мы заменим фон на красивую картинку, подходящую по смыслу к этому приложению, а пока сделаем нейтральный цвет, не бросающийся в глаза.
Для этого в панели навигатора откройте модуль “Main.storyboard”, выделите “View Controller”, затем в панели свойств откройте вкладку “Show the Attributes inspector”.
Найдите свойство “Background” и установите значение “White”.
Теперь найдите в библиотеке компонентов компонент “Table View Controller” и перетащите его в свободную область дизайнера рядом с “Supplies View Controller”, созданным в прошлом уроке.
Выделите только что добавленный компонент. Найдите кнопку в дизайнере “Show Document Outline”, нажмите на нее, откроется панель документов.
На этой панели разверните компонент “Table View Controller” и выделите компонент “Table View”. Затем в панели свойств откройте вкладку “Show the Attributes inspector”. Найдите свойство “Content”.
По умолчанию у этого свойства установлено значение “Dynamic Prototypes”, установите значение “Static Cells”, в дизайнере вы увидите, что интерфейс контроллера изменился и отобразилось 3 строки. Разберем значения этого свойства.
Значение “Dynamic Prototypes” используется, если вам необходимо иметь динамический набор данных, который будет постоянно изменяться. Установив это значение, обязательно необходимо переопределить методы протокола “UITableViewDataSource” для корректной работы контроллера.
Значение “Static Cells” используется, если вам необходимо иметь статические данные, которые не будут меняться. Установив это значение, вам не нужно переопределять методы протоколы “UITableViewDataSource”.
В данном примере мы устанавливаем это значение с целью удобства размещения элементов управления на нашей View. У нас будут ячейки с таким содержимым: ячейка под картинку, идентификатор товара, название товара, описание товара.
Сейчас у нас 3 ячейки, надо чтобы было 4. В первой ячейке будет компонент “Image View”, в остальных 2 ячейках будут элементы управления “Label” и “Text Field”, в последней 4-й ячейке будут элементы управления “Label” и “Text View”.
На панели документов для “Table View Controller” выделите компонент “Table View Section”. В панели свойств откройте вкладку “Show the Attributes inspector”. Найдите свойство “Rows”. Сейчас у этого свойство установлено значение “3”. Измените значение на “4”, у вас появится 4 ячейка.
В панели документов раскройте компонент “Table View Sections”, вы увидите список ячеек типа “Table View Cell”. Выделите первую ячейку. В панели свойств откройте вкладку “Show the Size inspector”. На этой вкладке можно управлять размерами компонента. Найдите свойство “Custom” и отметьте его галочкой. Затем найдите свойство “Row Height”. Установите значение этого свойства “144”, высота ячейки изменится.
Перетащите на эту ячейку из библиотеки компонентов компонент “Image View” и растяните его на всю область ячейки.
Выделите компонент “Image View” и нажмите кнопку “Pin”. В открывшемся диалоговом окне снимите галочку с поля “Constrain to margin” и отметьте позиционирование относительно всех стенок ячейки.
Нажмите кнопку “Add 4 Constraints”.
В панели документов выделите вторую ячейку. Перетащите из библиотеки компонентов компонент “Label” на эту ячейку. Поместите его с левого края ячейки и растяните по высоте ячейки.
В панели свойств откройте вкладку “Show the Size inspector”, установите свойство “Width” в значение “120”. Откройте вкладку “Show the Attributes inspector”, установите безымянное свойство с текстом “Label” на текст “Идентификатор”.
Найдите свойство “Font”, нажмите на кнопку со значком “T”, откроется диалоговое окно задания свойств шрифта. Установите свойство “Style” в значение “Bold”, свойство “Size” в значение “12”. Нажмите кнопку “Done”.
Представление должно выглядеть так:
Из библиотеки компонентов перетащите компонент “Text Field” и расположите рядом с компонентом “Label”. Растяните компонент “Text Field” на оставшуюся ширину ячейки.
Выделите элемент управления “Label”, нажмите кнопку “Pin”. Снимите галочку с поля “Constrain to margin”, отметьте позиционирование относительно верхней и левой стенок ячейки. Отметьте галочкой поле “Height”.
Нажмите кнопку “Add 3 Constraints”. Выделите элемент управления “Text Field”, нажмите кнопку “Pin”. В диалоговом окне снимите галочку с поля “Constrain to margin”, установите позиционирование относительно левой, верхней, правой стенок ячейки, отметьте галочкой поле “Height”.
Нажмите кнопку “Add 4 Constraints”.
В панели документов выделите 3 ячейку. Повторите для нее все операции, которые были применены ко второй ячейке. Измените текст элемента управления “Label” на “Название”. Должно получиться вот так:
В панели документов выделите последнюю ячейку, на вкладе “Show the Size inspectors” установите в поле “Row Height” значение “144”, предварительно отметив поле “Custom” галочкой. Перенесите на ячейку два компонента “Label” и “Text View”. В Установите ограничения для элемента управления “Label”, как мы устанавливали для предыдущих элементов управления “Label”, а для элемента управления “Text View” такие же ограничения, как для “Text Field”.
Для элемента управления “Label” установите текст “Описание”, для элемента управления “Text View” уберите текст по умолчанию. Должно получиться вот так:
В панели навигатора, добавьте новый модуль “Swift File” с именем “ProductViewController.swift”. Измените код, как показано ниже:
Перейдите снова в дизайнер , выделите “Table View Controller”, с которым проводили изменения, в панели свойств, откройте вкладку “Show the Identity inspector”. Установите свойство “Class” значением “ProductViewController”, свойство “Storyboard ID” значением “ProductViewController”.
В панели инструментов нажмите кнопку “Show the Assistant editor”.
Для элемента управления “Image View” создайте переменную с именем “imageView”.
Во второй ячейке, для элемента управления “Text Field”, создайте переменную с именем “idTxt”.
В третьей ячейке, для элемента управления “Text Field”, создайте переменную с именем “nameTxt”.
В четвертой ячейке, для элемента управления “Text View”, создайте переменную с именем “descriptionTxt”. Должно получиться вот так:
В панели навигатора, добавьте новый модуль “Swift File” с именем “ProductModel.swift”. Добавьте в него следующий код:
Разберем добавленный код построчно.
На 9 строке мы подключили пространство имен “Foundation” для класса “NSObject”.
На 11 строке мы объявили класс с именем “ProductModel”, который наследуется от класса “NSObject” для того, чтобы считаться типом данных.
На 12 строке мы объявили переменную с именем “productId” типа “Int” и инициализировали ее значение по умолчанию “-1”.
На 13 строке мы объявили поле с именем “productImage” типа “String” и инициализировали ее значение по умолчанию “”.
На 14 строке мы объявили поле с именем “productName” типа “String” и инициализировали ее значение по умолчанию “”.
На 15 строке мы объявили поле с именем “productDescription” типа “String” и инициализировали ее значение по умолчанию “”.
На 17 строке мы объявили параметризированный инициализатор класса “ProductModel” (это тоже самое, что и конструктор в языке программирования C#).
Инициализатор - это метод, который вызывается при создании нового экземпляра класса. Данный инициализатор принимает аргументы с такими же именами, как имена полей в классе.
Для того, чтобы инициализировать внутренние поля класса значениями полей аргументов. Мы левым операндом обращаемся к самому себе, через ключевое слово “self” и обращаемся к нужному нам полю, а правым операндом задаем значение аргумента.
Мы плавно подходим к созданию делегата. В панели навигатора добавьте новый модуль “Swift File” с именем “ProductProtocol.swift”. Добавьте в него следующий код:
Разберем добавленный код.
На 11 строке мы объявили протокол с именем “ProductProtocol”. Протокол - это тоже самое, что и интерфейс в языке программирования C#. Экземпляр протокола через инициализатор создать нельзя, поскольку это только прототип, который не содержит реализации и используется в качестве описания и задания соглашений, которые разработчик должен реализовать сам в будущем.
На 12 строке мы объявили метод прототип с именем “changeProduct”, который принимает аргумент типа “ProductModel” с именем “model”.
Откройте модуль “ProductViewController.swift”, добавьте поле с именем “delegate” типа “ProductProtocol?” и поле с именем “id” типа “Int” со значением по умолчанию “-1”. Должно получиться вот так:
Добавьте после метода “viewDidLoad”, новые методы с именами “initNavigationButtons”, “backToParent”, “saveData”, которые ничего не принимают и ничего не возвращают. Код:
Разберем построчно добавленный код.
На 21 строке мы вызываем метод “initNavigationButtons”, когда View находится в процессе загрузки, чтобы инициализировать кнопки навигации.
На 24 строке мы объявили метод с именем “initNavigationButtons”.
На 25 строке мы переопределяем левую кнопку навигации, задаем ей текст “Отмена” и обработчик события на нажатие, метод “backToParent”.
На 26 строке мы создаем кнопку с именем “saveButton” и текстом “Сохранить”, добавляем для нее обработчик событие на нажатие, метод “saveData”.
На 27 строке мы обращаемся к экземпляру панели навигации контроллера “navigationItem” и вызываем от него метод “setRightBarButton”, который принимает два аргумента. Первый аргумент - это экземпляр добавляемой на панель навигации кнопки, второй аргумент - это стиль добавления кнопки, добавить с анимацией или без.
Сам метод, как видно из названия, добавляет кнопку справа на панель навигации. Это вариант, как добавить правую кнопку из кода.
На 30 строке мы объявили метод с именем “saveData”.
На 31 строке мы обращаемся к нашему делегату с именем “delegate” и проверяем, если он инициализирован, тогда вызываем у него метод “changeData” и передаем туда модель данных, заполненную данными собранными с элементов управления.
На 32 строке мы создаем экземпляр типа “ProductModel” с именем “model”.
На 33 строке мы вызываем у делегата метод “changeData” и передаем туда экземпляр “model”. Данный метод будет реализован в классе “SuppliesViewController”.
На 35 строке мы возвращаемся на предыдущую View (SuppliesViewController) в стеке иерархий вызовов View.
На 38 строке мы объявляем метод с именем “backToParent”. Данный метод делает переход на предыдущую View (SuppliesViewController) в стеке иерархий вызовов View.
Теперь откройте модуль “SuppliesViewController.swift”. Нам необходимо обновить его реализацию:
Разберем обновленный код построчно.
На 12 строке в классе SuppliesViewController мы наследуемся от протокола “ProductProtocol”.
На 13 строке мы заменили тип данных для поля “supplies”. Тип данных был “[String]”, стал “[ProductModel]”. И сделали это поле статическим для того, чтобы была возможность доступа к нему из контроллера “ProductViewController”.
На 29 строке мы реализовываем метод “changeProduct” протокола “ProductProtocol”. Именно этот метод будет вызываться при нажатии кнопки “Сохранить” в контроллере “ProductViewController”.
На 30 строке мы проверяем идентификатор продукта, если “-1” - это означает, что это новый продукт. Иначе существующий продукт, и мы его обновляем.
На 32 строке мы правым операндом генерируем идентификатор продукта путем вызова метода “makeNewProductId”. Данный метод возвращает значение типа “Int”, которое мы присваем левому операнду. Левый операнд - это поле “productId” экземпляра “ProductModel”.
На 33 строке мы добавляем новый продукт в коллекцию продуктов.
На 36 строке мы объявляем переменную с именем “changedIndex” типа “Int” со значением по умолчанию “-1”. В эту переменную мы запишем найденную ниже в цикле позицию продукта в коллекции “supplies”.
На 37 строке мы в цикле проходимся по элементам коллекции “supplies” и ищем продукт, который нужно обновить.
На 38 строке описано условие поиска продукта.
На 39 строке, когда продукт был найден, мы сохраняем его позицию в переменную “changedIndex”.
На 40 строке выходим из цикла.
На 43 строке проверяем, если продукт был найден , тогда обновляем этот продукт.
С 44 по 46 строку мы обновляем свойства продукта , значениями свойств модели, переданной аргументом метода “changeProduct”.
На 49 строке мы запускаем переинициализацию “DataSource” для табличного представления, чтобы данные в ячейках обновились и добавились/удались обновленные данные.
На 52 строке мы объявили метод с именем “makeNewProductId”, который ничего не принимает и возвращает значение типа “Int”.
На 53 строке левым операндом мы объявили переменную с именем “sortProducts” типа “[ProductModel]”. Правым операндом мы на экземпляре коллекции “supplies” вызываем метод “sorted”, который принимает лямбда метод сортировки коллекции объектов и возвращает отсортированную коллекцию.
У лямбда метода есть два аргумента, в них находятся экземпляры сравниваемых объектов из коллекции “suppliers”. Данный метод возвращает значение типа “Bool”.
На 54 строке мы возвращаем условие сортировки по возрастанию. Сортировка производится по свойству “productId” класса “ProductModel”.
На 56 строке мы обращаемся к последнему элементу отсортированной коллекции, тем самым получаем максимальный идентификатор продукта в коллекции и увеличиваем его на единицу.
Теперь надо обновить реализацию метода “cellForRowAt indexPath”:
Разберем код построчно.
На 69 строке мы изменили вид обращения к коллекции “supplies”.
На 73 строке мы изменили для экземпляра ячейки тип стиля. Был “.plain”, стал “subtitle”.
На 74 строке мы левым операндом объявили константу с именем “model” типа “ProductModel”. Правым операндом мы инициализируем константу значением из коллекции “supplies”.
На 75 строке мы записываем в свойство “tag” идентификатор продукта для этой ячейки.
На 76 строке в элемент управления “Label”, который находится в верхней области ячейки, мы записываем название продукта.
На 77 строке в элемент управления “Label”, который находится в нижней области ячейки, мы записываем описание продукта.
На 78 строке мы активируем в ячейке информационную кнопку справа. При нажатии на эту кнопку мы будем редактировать продукт.
Теперь нам надо подвязаться на событие нажатия на информационную кнопку в ячейке.
Для этого необходимо переопределить метод протокола “UITableViewDelegate” ,реализованного в классе “UITableViewController” с именем “accessoryButtonTappedForRowWith”.
Разберем код построчно.
На 83 строке мы получаем экземпляр типа “ProductModel”, привязанный к ячейке, и сохраняем его в константу с именем “model”.
На 84 строке мы производим поиск контроллера с именем “ProductViewController” в модуле “Main.storyboard”.
На 85 строке на найденном экземпляре контроллера обращаемся к свойству “delegate” типа “ProductProtocol” и инициализируем его ссылкой на самого себя, тем самым говоря, что в этом классе уже реализован метод этого протокола с именем “changeProduct” и вызывать метод надо именно из этого класса.
На 86 строке мы на найденном экземпляре контроллера обращаемся к свойству “id” и инициализируем его идентификатором продукта, привязанного к текущей ячейке.
На 87 строке мы открываем контроллер “ProductViewController”.
Редактирование мы почти сделали, осталось добавить инициализацию редактируемых данных в контроллере “ProductViewController”.
Давайте реализуем еще в этом контроллере удаление данных. Для этого надо переопределить два метода объявленных в протоколе “UITableViewDelegate” и реализованных в классе “UITableViewController”. Эти методы называются “canEditRowAt IndexPath” и “commit editingStyle”. Обновите свой код в соответствии с представленным ниже:
Разберем код построчно.
На 90 строке мы переопределили метод “canEditRowAt IndexPath”, данный метод возвращает значение , которое говорит о том, активировать удаление строк или нет.
На 91 строке возвращаем значение активировать.
На 94 строке мы переопределили метод “commit editingStyle”, данный метод вызывается, когда мы нажали кнопку удалить на ячейке.
На 95 строке мы удаляем продукт из коллекции “supplies”.
На 96 строке обновляем содержимое таблицы.
Теперь добавим кнопку добавления нового товара. Для этого обновим код метода “initNavigationButtons”.
Разберем код построчно.
На 100 строке мы создали экземпляр кнопки с текстом “Новый продукт” и обработчиком события на нажатие - метод “newProduct”.
На 101 строке мы добавили выше созданную кнопку в панель навигации контроллера в область справа.
На 104 строке мы объявили метод “newProduct”, которые ничего не принимает и ничего не возвращает.
На 105 строке мы производим поиск контроллера “ProductViewController” в модуле “Main.storyboard”.
На 106 строке мы на найденном экземпляре контроллера обращаемся к свойству “delegate” и инициализируем его ссылкой на самого себя.
На 107 строке мы на найденном экземпляре контроллера обращаемся к свойству “id” и говорим, устанавливая значение “-1”, что мы создаем новый продукт.
Теперь откройте модуль “Main.storyboard”, в нем на контроллере “ProductViewController” выделите элемент управления с идентификатором “idTxt”.
В панели свойств на вкладке “Show the Attributes inspector” найдите свойство “User Interaction Enabled” и снимите галочку. Тем мы самым мы запретили редактирование значения этого поля.
Теперь перейдите в модуль “ProductViewController.swift”. Обновите в нем код, как это показано ниже:
Разберем добавленный код построчно.
На 19 строке мы добавили метод с именем “initData”, который ничего не возвращает и принимает аргумент с именем “id” типа “Int”.
На 20 строке мы проверяем идентификатор продукта, если он больше значения “-1”, значит продукт уже существует и содержит внутри себя данные, которые можно отобразить на текущей View.
На 22 строке мы ищем продукт по идентификатору продукта, переданному аргументом в методе в коллекции продуктов “supplies”.
С 23 по 25 строку мы заполняем элементы управления на пользовательском интерфейсе данными найденного продукта.
На 33 строке в методе “viewDidLoad” мы добавили вызов метода “initData” и передали ему аргумент поле “id”, которое мы задаем в контроллере “SuppliesViewController”.
Запустите приложение.
На анимации выше видно, что мы вошли в систему, открыли товар на редактирование, откредактировали товар и изменения сохранились. Затем удалили товар.
Теперь давайте проверим добавление нового товара:
Проверили, добавление нового товара работает хорошо. Но все равно есть один нюанс, наше приложение на русском языке. А когда выполняли на ячейки жест справа на- лево, то показывалась кнопка удалить “Delete” на английском, давайте исправим это, чтобы показывалось русское название “Удалить”.
Откройте модуль “SuppliesViewController.swift”, нам необходимо переопределить метод, объявленный в делегате “UITableViewDelegate” c именем “titleForDeleteConfirmationButtonForRowAt” и реализованный в классе “UITableViewController”. Добавьте следующий код, после метода “backToParent”:
Я думаю, этот метод не стоит разбирать построчно, тут и так все понятно.
Запустите приложение.
На этом завершим наш урок.
В следующем уроке мы разберем технологию 3D Touch и применим ее к нашему приложению для предварительного просмотра товаров. Добавим поле поиска в заголовок контроллера со списком товаров, реализуем поиск товаров. Реализуем протокол “UITextFieldDelegate”, чтобы скрывать клавиатуру при нажати кнопки “Ввод” на клавиатуре мобильного устройства. Разберем, как добавить собственную панель интрументов с кнопками.
Тайм-менеджмент для програміста, як встигнути всі?
Автор: Редакция ITVDN
Опять не выспались, потому что всю ночь кодили, учились, искали баги? Не сходили на обед, потому что дел выши крыши, плюс еще и весь небесный свод усыпан задачами? Забываете сделать обещанное, вспоминаете в последнюю секунду о встрече или запланированном мероприятии? Вы круглые сутки пашете, аки конь, но без результатов? Остановитесь, выдохните, вам надо заняться планированием и освоить азы тайм-менеджмента.
Не секрет, что в IT почва для планирования не шибко благодатная. Сколько бы ни придумали систем, все равно всегда есть место форс-мажору, заваленным проектам, испорченным нервам. В большинстве случаев так происходит не потому, что системы плохие, а потому что каждый конкретный человек, принимающий участие, например, в разработке, должен организовываться самостоятельно и уметь распределять дела, а у него не очень то и получается.
В этой статье мы поговорим с вами, как начать с себя, чтобы и у вас все успевалось, и у тех, с кем вы взаимодействуете, тоже. Как говорил кто-то очень умный и просвещенный, работать нужно не 12 часов в сутки, а головой. Ладно, мы знаем, это фраза Стива Джобса. =)
Итак, как же успевать все?
Планирование
Да, это банально, скучно и уныло. Но это работает. Более того, планирование смело можно считать одним из основных столпов грамотного распределения времени. Чтобы планирование было успешным, вам нужно любое место, куда писать:
- милый блокнот и мягкий карандаш,
- любимый девайс с приложением,
- "вездедоступный" онлайн календарь,
- почтовый клиент…
В общем, подойдет абсолютно любое человеческое изобретение, где есть даты и куда можно записать что-то. Выберите время суток, когда вы можете выделить 10 минут и спокойно поразмыслить о делах. Кому-то удобнее этим заниматься утром, перед работой, занятиями и т. д. Кто-то спокойнее отдается планированию вечером перед сном. Поставьте себе на это время напоминание. Сначала вам будет тяжело, обременительно, но с каждый днем привычка планировать будет укореняться, а разгребать завалы дел вы будете быстрее и успешнее.
Сложное и простое
Часто бывает, что одна задача очень большая и необъятная. И она такая страшная, что порой даже не знаешь, как к ней подойти. В таком случае выручает разбивание огромного на что-то маленькое. То есть, одной большой задачи - на подзадачи. Согласитесь, перенести огромный стеллаж с книгами за один раз — это непосильно и нереально. Но если вытащить книги, разложить их на стопки, а шкаф разобрать, то справиться с этим будет намного проще и быстрее.
Составляйте ваш список дел на день так, чтобы в нем было несколько простых, но нужных дел, например, разобрать почту, позвонить маме, заказать книгу и - более сложных. Выполнение простых задач обычно стимулирует и вы видите, как список сокращается, входите во вкус и завершаете все!
Мультизадачность
Она не работает и ее не существует. Это миф. И Юлий Цезарь со своими умениями не показатель. Наш мозг не умеет делать 2 дела одновременно и параллельно, ну не поддерживает он многопоточность. Даже когда вам кажется, что вы успешно сели на два стула - вы себя обманываете. Вы просто переключаетесь с одной задачи на другую. При этом с каждым переключением вспомнить о том, что вы делали по этой задаче раньше, становится все труднее и труднее и, как следствие, вы быстрее устаете. У вас болит голова, вы больше тратите времени, чтобы завершить начатое. И, в общем-то, либо ничего не успеваете, либо посредственно справляетесь с заданиями. Всегда делайте задачи одна за другой. Поверьте, последовательность — это идеальный помощник в решении сложных дел. Одно дело сделали — вычеркнули, наградили себя вкусным кофе, побежали делать следующее.
Приоритеты
Итак, мы договорились с вами, что будем планировать. Записали, все что нужно сделать, разбили сложные задачи на подзадачи, а как же сделать так, чтобы не перескакивать с одного дела на другое? В этом нам помогут приоритеты.
Как бы это странно ни звучало, но не бывает задач одинаково важных в один и тот же момент времени. Давайте рассмотрим на жизненном примере. Каждый водитель, подъезжающий к перекрестку, где есть светофор, помимо него также видит перед собой знак, который сообщает ему о том, что он на главной дороге, например, и может свободно ехать. Но вот вам ситуация: светофор горит красным, а знак говорит — поезжай. Стоять и ехать одновременно невозможно. Как решается эта ситуация? Правильно, приоритетами. У светофора он выше, значит, когда горит красный, какой бы знак ни висел, машина — стоит. Если же не работает светофор, то в силу вступает знак. И все.
Так же вы можете поступать со своими делами, решая, какая задача из списка более важная и нужная, а какая может подождать и подняться вверх только после выполнения более важной, а какую можно и вовсе не делать — никто не умрет, заводы и пароходы не остановятся.
Если же вам трудно сразу научиться расставлять приоритеты, почитайте о матрице Эйзенхауэра. Все ваши задачи можно разделить на 4 категории:
Срочные и важные,
Важные, но не срочные,
Срочные, но неважные,
Несрочные и неважные.
С таким подходом выполнять намеченное станет еще проще.
Время
У каждого из нас есть рутинные дела. И обычно мы приблизительно знаем, сколько тратим на них времени. Значит, мы можем четко прописывать, что на чтение почты и ответы на письма мы отводим 30 минут, например. Более того, ограничение по времени можно превратить в игру. Каждый раз пытаться побить рекорд предыдущего дня. Например, сегодня вы работали с почтой 30 минут, а завтра попробуйте справиться за 28. Так становится немного веселее.
Существуют дела без времени, например чтение профессиональной литературы. Тут проще, отведите себе какое-то время, например, час, поставьте таймер и садитесь читать. Время вышло — задача выполнена.
Следите за тем, как вы проводите свое время. Бывает, нам кажется, что мы так много работали, но ничего не сделали, хотя на самом деле, львиную долю рабочего дня мы просидели в социальных сетях. В общем-то, четкое планирование должно вас оградить от зыбучих песков интернета, но если вы уже и решили себя порадовать очередным спором в интернете, то также ограничьте это по времени.
Не делайте этого
Если вы понимаете, что то, что вам предстоит сделать, будет приносить вам страдания — не делайте это. Просто остановитесь и откажитесь, передайте эту задачу другому, забудьте о ней. Поверьте, всегда есть люди, которые сделают это за вас и никто не пострадает. Зато вы спокойно будете заниматься другими важными делами, а не страдать над подходами к выполнению намеченного. Если вся ваша работа причиняет вам боль, значит пора менять либо работу, либо профессию. Серьезно. В общем, старайтесь делать меньше того, что вам не нравится.
Отдыхайте
От работы дохнут кони, ну а я - бессмертный пони? Это про вас? Значит, выдохните. Знаете, если вы сегодня уйдете вовремя, небесная твердь не свалится, планеты не сойдут с орбит. А если вы завтра и вовсе возьмете отгул, то тоже ничего страшного не произойдет. Найдите для себя занятие, которое поможет вам расслабиться. И, да, запланируйте на него время. Это может быть все, что угодно: спорт, чтение, вышивание, прогулки, медитации и прочее, прочее. И спите, обязательно давайте мозгу время перезагрузиться и восстановиться, тогда вам все будет по плечу!
А теперь небольшой свод коротких правил, которые дополнят и уточнят все вышесказанное:
1. Планируйте и проставляйте приоритеты.
2. Ставьте на все задачи временные рамки, желательно, чтобы эти рамки не выходили за пределы рабочего времени (если мы говорим о рабочих делах).
3. Перерывы и отдых тоже планируйте.
4. В списке дел должны быть разные задачи: легкие, средние и посложнее.
5. Фиксируйте намеченное и вычеркиваете сделанное.
6. Мотивируйте себя музыкой, перерывом или чем-то еще приятным.
7. Разбивайте большие задачи на маленькие.
8. Суперконцентрация. Если нужно, а никак не получается — отключите все раздражители, уйдите в другую комнату, в общем, сделайте все, чтобы вы остались со своим заданием наедине.
9. Не делайте то, что вам не нравится.
10. Любите себя и берегите!