что такое outlet swift
Core Data + Swift для самых маленьких: необходимый минимум (часть 3)
Это заключительная часть статьи о Core Data, предыдущие части доступны здесь: часть 1 и часть 2.
В этой статье мы повернемся лицом к пользователю и поработаем над интерфейсной частью, помогать нам в этом будет NSFetchRequest и NSFetchedResultsController. Данная часть получилась довольно большой, но я не вижу смысла дробить ее на несколько публикаций. Аккуратнее, под катом много кода и картинок.
Интерфейс — вещь неоднозначная и, в зависимости от требования к продукту, может существенное меняться. В данной статье я не буду уделять ему слишком много времени, точнее говоря, буду уделять совсем мало (я имею ввиду следование Guidelines и тому подобное). Моя задача в данной части статьи состоит в том, чтобы показать, как Core Data может очень органично вписаться в элементы управления iOS. Поэтому я буду использовать для этих целей такой интерфейс, при использовании которого взаимодействие элементов управления и Core Data будет выглядеть проще и нагляднее. Очевидно, что в реальном приложении интерфейсной части надо будет посвятить гораздо больше времени.
Справочники
Прежде чем начать, давайте придадим модулю делегата приложения ( AppDelegate.swift ), в котором мы экспериментировали в прошлой части статьи, первоначальный вид.
Я не буду здесь использовать Prototype Cells и создавать «кастомный» класс для ячеек таблицы (чтобы сосредоточиться на других вещах), поэтому давайте установим количество таких ячеек равным нулю ( Attributes Inspector\Table View\Prototype Cells ).
Теперь нам требуется определить источник данных, чтобы реализовать протокол Table View Data Source. В прошлой части мы познакомились с NSFetchRequest и, на первый взгляд, он вроде как подходит для этой цели. С его помощью можно получить список всех объектов в виде массива, что, собственно, нам и нужно. Но мы хотим не только смотреть на список Заказчиков, мы хотим их добавлять, удалять и редактировать. В этом случае, нам придется отслеживать все эти изменения вручную и каждый раз, опять вручную, обновлять наш список. Звучит не очень, да? Но есть другой вариант — NSFetchedResultsController, он очень похож на NSFetchRequest, но он не только возвращает массив нужных нам объектов в момент запроса, но и продолжает следить за всеми записями: если какая-то запись измениться — он нам сообщит об этом, если какие-нибудь записи подгрузятся в фоне через другой управляемый контекст — он нам тоже сообщит об этом. Нам останется только обработать это событие.
Давайте реализуем NSFetchedResultsController в нашем модуле. Я сначала приведу весь код, а следом прокомментирую.
Затем, при загрузке нашего View Controller ( func viewDidLoad() ) мы запускаем fetchedResultsController на выполнение:
Прежде чем продолжать, давайте кое-что немного оптимизируем — создание объекта NSFetchedResultsController не отличается лаконичностью, а нам его надо будет также создавать и для других наших сущностей. При этом, по сути, меняться будет только имя сущности и, возможно, имя поля сортировки. Чтобы не заниматься «копи-пастой» давайте вынесем создание этого объекта в CoreDataManager.
С учетом этого, определение fetchedResultsController измениться на следующее:
Теперь нам надо сделать так, чтобы при выборе какого-нибудь Заказчика открывалась «карточка» со всеми его данными, которые, при необходимости, можно было редактировать. Давайте для этого добавим еще один View Controller (зададим ему заголовок «Customer» ) и соединим его с нашим Table View Controller.
И указываем этот класс для нашего нового View Controller.
Теперь добавим Navigation Bar с двумя кнопками (Save — для сохранения изменений и Cancel — для отмены). Также нам необходимы два текстовых поля для отображения и редактирования информации (name и info). Сделаем два Action (для Save и Cancel) и два Outlet (для name и info).
Также, нам надо учесть то, что у нас есть обязательное для заполнение поле — name. Если пользователь попробует сохранить Заказчика с пустым именем, то он получит критическую ошибку. Чтобы этого не произошло, давайте добавим проверку корректности сохраняемых данных: если данные не корректные, то будем показывать соответствующую предупреждение и блокировать запись такого объекта. Пользователь должен либо ввести корректные данные, либо отказаться от записи такого объекта.
И последнее, что нам надо здесь учесть: наверняка, нам захочется не только редактировать существующих Заказчиков, но и добавлять новых. Делать это мы будем следующим образом: в списке Заказчиков добавим кнопку для создания нового Заказчика, которая будет открывать нашу «карточку» передавая в нее nil. А при сохранении данных «карточки» Заказчика мы будем проверять, если объект customer у нас еще не создан (то есть это ввод нового Заказчика), то будем его сразу создавать.
Таким образом, у нас получиться примерно следующий код.
Этот Action будет открывать «карточку» для создания нового Заказчика, передавая в нее nil.
Осталось сделать так, чтобы при выборе какого-нибудь существующего Заказчика, открывалась его «карточка». Для этого нам понадобиться две процедуры.
В первой процедуре (при выделении строки списка) мы «считываем» текущего Заказчика, а во второй (при переходе из списка в «карточку») — присваиваем ссылку на выбранного Заказчика переменной customer нашей «карточки», чтобы при ее открытии мы могли считать все данные объекта.
Давайте теперь запустим наше приложение и убедимся, что все работает как надо.
Приложение работает, мы можем вводить новых Заказчиков, редактировать существующих, но информация в списке автоматически не обновляется и у нас нет механизма, чтобы удалять ненужного (или ошибочно введенного) Заказчика. Давайте это исправим.
Так как мы здесь используем NSFetchedResultsController, который «знает» о всех этих изменениях, то нам надо просто его «послушать». Для этого надо реализовать протокол делегата NSFetchedResultsControllerDelegate. Объявим, что мы реализуем этот протокол:
Объявим себя делегатом NSFetchedResultsController:
И добавим следующую реализацию этого протокола:
Осталось только реализовать удаление Заказчика. Это делается довольно просто, нам понадобиться переопределить всего одну небольшую процедуру.
На этом работа со справочником «Заказчики» завершена. Давайте запустим приложение и проверим его работу.
Как видете, ничего сверхсложного, Core Data прекрасно сочетается со стандартными элементами интерфейса.
Справочник «Услуги»
Опционалы в Swift
Несмотря на некоторый опыт в мобильной разработке (в том числе с применением Swift), регулярно на почве свифтовых опционалов возникали ситуации, когда я знал что нужно делать, но не совсем внятно представлял, почему именно так. Приходилось отвлекаться и углубляться в документацию — количество «заметок на полях» пополнялось с удручающей периодичностью. В определенный момент они достигли критической массы, и я решил упорядочить их в едином исчерпывающем руководстве. Материал получился довольно объемным, поскольку предпринята попытка раскрыть тему максимально подробно. Статья будет полезна как начинающим Swift-разработчикам, так и матерым профессионалам из мира Objective-C — есть ненулевая вероятность, что и последние найдут для себя что-то новое. А если не найдут, то добавят свое новое в комментарии, и всем будет польза.
Что такое Optionals?
Optionals (опционалы) — это удобный механизм обработки ситуаций, когда значение переменной может отсутствовать. Значение будет использовано, только если оно есть.
Зачем нужны Optionals, когда есть проверка на nil?
Во-первых, проверка на равенство/неравенство nil применима только к nullable-типам и не применима к примитивным типам, структурам и перечислениям. Для обозначения отсутсвия значения у переменной примитивного типа приходится вводить спецзначения, такие как NSNotFound.
NSNotFound не только нужно рассматривать как спецзначение, но и следить, чтобы оно не входило в множество допустимых значений переменной. Ситуация усложняется еще и тем, что NSNotFound считается равным NSIntegerMax, т.е. может иметь разные значения для разных (32-bit/64-bit) платформ. Это значит, что NSNotFound нельзя напрямую записывать в файлы и архивы или использовать в Distributed Objects.
Соответственно, пользователь этой переменной должен учитывать, что спецзначения возможны. В Swift даже примитивный тип можно использовать в опциональном стиле, т.е явным образом указывать на то, что значения может не быть.
Как это работает?
В документации значение по умолчанию в случае отсутсвия явного присвоения не упоминается, но сказано, что опционал represents either a wrapped value or nil, the absence of a value. Если опциональная переменная объявлена без явного присвоения (какое-либо Some не присваивалось), то логично следует, что неявно присваивается None — третьего «неинициализрованного» состояния у опционалов нет.
По факту опционал представляет собой системное перечисление:
Перечисление Optional имеет два конструктора. Первый конструктор init(_ some: Wrapped) принимает на вход значение соответсвующего типа, т.е. следующие записи эквивалентны:
Второй конструктор init(nilLiteral: ()) является реализацией протокола ExpressibleByNilLiteral
что логично, поскольку преобразование пустого кортежа Void () в nil несколько неочевидно.
Вместо этого конструктора следует использовать
или вообще не использовать явное присвоение
поскольку nil будет присвоен по умолчанию.
Идиомы использования
Нет особого смысла использовать обычное перечисление с двумя состояниями. Вполне можно реализовать подобный механизм самостоятельно: создать enum c двумя состояниями и конструкторами для соответствующих значений, добавить какой-нибудь постфиксный оператор для Force Unwrapping (например, как это сделано здесь), добавить возможность сравнения с nil или вообще придумать «свой» nil и т.д. Опционалы должны быть интегрированы непосредственно в сам язык, чтобы их использование было естественным, не чужеродным. Разумеется, можно рассматривать такую интеграцию как «синтаксический сахар», однако языки высокого уровня для того и существуют, чтобы писать (и читать) код на них было легко и приятно. Использование опционалов в Swift подразумевает ряд идиом или особых языковых конструкций, которые помогают уменьшить количество ошибок и сделать код более лаконичным. К таким идиомам относятся Implicit Unwrapping, Optional Chaining, Nil-Coalescing и Optional Binding.
Implicit unwrapping
В вызове sayHello(times: my_variable2) извлечение значения 42 из my_variable2 все равно осуществляется, только неявно. Использование неявно извлекаемых опционалов делает код более удобным для чтения — нет восклицательных знаков, которые отвлекают внимание (вероятно, читающего код будет беспокоить использование Force Unwrapping без предварительной проверки). На практике это скорее анти-паттерн, увеличивающий вероятность ошибки. Неявно извлекаемый опционал заставляет компилятор «закрыть глаза» на то, что опционал используется в неопциональном контексте. Ошибка, которая может быть выявлена во время компиляции (вызов sayHello(times: my_variable1) ), проявится только в рантайме (вызов sayHello(times: my_variable3) ). Явный код всегда лучше неявного. Логично предположить, что такое снижение безопасности кода требуется не только ради устранения восклицательных знаков, и это действительно так.
Неявно извлекаемые опционалы позволяют использовать self в конструкторе для иницализации свойств и при этом:
Наглядный пример, где требуется использовать self в конструкторе для иницализации свойств, приведен в документации:
Optional Chaining
Nil-Coalescing
Возможность использовать выражения в качестве правого операнда позволяет создавать цепочки из умолчаний:
Optional Binding и приведение типов
В официальной документации детали реализации Optional Binding не описаны, но можно построить модель, хорошо описывающую поведение этого механизма.
Таким образом, оператор опционального приведения as? порождает опционал, который часто используется в связке с Optional Binding:
map и flatMap
Методы map и flatMap условно можно отнести к идиомам Swift, потому что они определены в системном перечислении Optional:
Опционалы и обработка исключений
Опционалы и Objective-C
Трансляция из Objective-C в Swift осуществлятся по следующим правилам:
Правила передачи опционалов из Swift в Objective-C несколько проще:
Резюме, синтаксис
Заключение
Нулевой указатель — это ошибка на миллиард долларов. Вызывающая сторона все равно должна учитывать контекст и проверять результат на равенство специфичной константе, означающее отсутствие данных. Тот факт, что константа null всего одна, принципиально ситуацию не меняет и лишь добавляет неожиданностей при приведении типов.
Факт отсутствия данных должен обрабатываться отдельной сущностью, внешней по отношению к самим данным. В С++ или Java в область допустимых значений указателя включено специальный «адрес», обозначающий отсутствие адресата. «Правильный» указатель не может существовать без адресата, следовательно, не может «осознать» отсутствие адресата. Даже человеку, т.е. довольно сложной системе, приходится довольстоваться аксиомой Cogito, ergo sum (лат. — «Мыслю, следовательно существую»). У человека нет достоверных признаков собственного бытия или небытия, но у внешних по отношению к человеку сущностей эти критерии есть. В Swift такой внешней сущностью является опционал.
Дополнительные материалы
UPD: (by Alexander Zimin) Конструктор init(nilLiteral: ()) напрямую вызвать на самом деле можно:
Тем не менее, в документации от Apple не рекомендуется это делать.
Собеседование: Swift. Вопросы и ответы
Языку программирования Swift всего четыре года, но он уже становится основным языком разработки для iOS. Развиваясь до версии 5.0, Swift превратился в сложный и мощный язык, отвечающий как объектно-ориентированной, так и функциональной парадигме. И с каждым новым релизом в нем добавляется еще больше возможностей.
Но насколько хорошо вы на самом деле знаете Swift? В этой статье вы найдете примеры вопросов для собеседования по Swift.
Вы можете использовать эти вопросы для интервьюирования кандидатов, чтобы проверить их знания или вы можете проверить свои собственные. Если вы не знаете ответа, не переживайте: к каждому вопросу есть ответ.
Вопросы разделены на три группы:
Beginner
Рассмотрим следующий код:
Чему равны значения tutorial1.difficulty и tutorial2.difficulty? Была бы какая-то разница, если бы Tutorial был классом? Почему?
tutorial1.difficulty равен 1, а tutorial2.difficulty равен 2.
В Swift структуры — типы-значения (value type). Они копируются, а не ссылаются. Следующая строка копирует tutorial1 и присваивает её tutorial2:
Изменения в tutorial2 не отражаются на tutorial1.
Если бы Tutorial был бы классом, tutorial1.difficulty и tutorial2.difficulty равнялись бы 2. Классы в Swift — ссылочные типы (reference type). Когда вы меняете свойство tutorial1, вы увидите такое же изменение у tutorial2 — и наоборот.
Вы объявили view1 при помощи var, а view2 — при помощи let. В чём разница и скомпилируется ли последняя строка?
Да, последняя строка скомпилируется. view1 — это переменная, и вы можете назначить её значение новым экземпляром UIView. Используя let, вы можете присвоить значение лишь однажды, так что следующий код не скомпилируется:
Однако, UIView — это класс со ссылочной семантикой, так что вы можете изменять свойства view2 — что означает, что код скомпилируется.
Этот код сортирует массив по алфавиту. Максимально упростите замыкание.
Swift автоматически определяет тип параметров замыкания и возвращаемый тип, так что вы можете убрать их:
Вы можете заменить имена параметров использованием нотации $i:
Замыкания, состоящие из одного оператора, могут не содержать ключевое слово return. Значение последнего выполненного оператора становится возвращаемым результатом замыкания:
Наконец, так как Swift знает, что элементы массива соответствуют протоколу Equatable, вы можете просто написать:
Upd: hummingbirddj упростил ещё больше:
В данном случае можно еще короче: – сортирует по возрастанию, работает для типов, реализующих Comparable.
Этот код создаёт два класса: Address и Person. Также создаются два экземпляра класса Person (Ray и Brian).
Предположим, что Brian переехал по новому адресу и вы хотите обновить его запись следующим образом:
Это компилируется и выполняется без ошибок. Но, если вы проверите теперь адрес Ray, то вы увидите, что он тоже «переехал».
Что здесь произошло и как мы можем исправить это?
Что такое optional и какие проблемы они решают?
Коротко перечислите основные отличия между structure и class.
Что такое generics и для чего они нужны?
В Swift вы можете использовать generics в классах, структурах и перечислениях.
Generics устраняют проблему дублирования кода. Если у вас есть метод, который принимает параметры одного типа, иногда приходится дублировать код, чтобы работать с параметрами другого типа.
Например, в этом коде вторая функция — это «клон» первой, за исключением того, что у неё параметры string, а не integer.
Применяя generics, вы совмещаете две функции в одной и одновременно обеспечиваете безопасность типов:
Так как вы тестируете равенство, вы ограничиваете типы теми, которые отвечают протоколу Equatable. Этот код обеспечивает требуемый результат и препятствует передаче параметров неподходящего типа.
В некоторых случаях не получится избежать неявного разворачивания (implicitly unwrapped) optionals. Когда и почему?
Наиболее частые причины для использования implicitly unwrapped optionals:
Какими способами можно развернуть optional? Оцените их в смысле безопасности.
Принудительное развёртывание (forced unwrapping) — небезопасно.
Неявное развертывание при объявлении переменной — небезопасно.
Optional binding — безопасно.
Optional chaining — безопасно.
Nil coalescing operator — безопасно.
Оператор Guard — безопасно.
Optional pattern — безопасно.
Обзор системы переводов SWIFT
Что такое SWIFT и как он возник?
Аббревиатура SWIFT расшифровывается как Society for Worldwide Interbank Financial Telecommunications. В переводе это значит «Сообщество всемирных межбанковских финансовых телекоммуникаций», основной целью которого является передача информации и совершение платежей в международном формате.
Предпосылки к созданию системы SWIFT были замечены еще в начале 50-х годов 20 века, когда, спустя несколько лет после Второй Мировой войны, государства начали заниматься активной торговлей на международном уровне. Как результат, это повлекло за собой резкое увеличение банковских функций и операций. Ранее общение между банками совершалось посредством почты и телеграфа, однако новые условия диктовали новые правила – такие способы передачи информации стали неэффективными из-за стремительного увеличения объема банковских операций. Более того, очень часто стали возникать недоразумения и ошибки во время проведения межбанковских операций, связанные с системами функционирования различных банков и отсутствием необходимой стандартизации. Банкиры понимали, что рано или поздно возникнет новый способ бумажного обмена финансовой информации между всеми банками мира. И они были правы…
Разработка такой системы началась в начале шестидесятых годов. Представители шестидесяти крупнейших европейских и американских банков несколько раз собирались для обсуждения волнующей всех проблемы – создания единой системы стандартизации в банковской сфере. Для этой цели было решено использовать точную вычислительную технику – компьютеры, которые, как известно, обеспечивали максимально эффективную систему передачи данных такого рода.
Непосредственная работа над данной системой, способной круглосуточно обеспечивать обмен финансовой информацией с высокой защитой и под контролем, началась в начале 1968 года. Уже в 1972 создатели подготовили официальный проект и сделали необходимые расчеты по рентабельности этой системы.
В мае 1973 года при участии 239 банков, расположенных в 15 странах мира, была создана и учреждена платежная система под названием SWIFT. Её разработчики трудились более четырех лет для практического осуществления этого учреждения, и 9 мая 1977 года международная сеть, отвечающая за передачу данных, была официально запущена. В конце этого же года число банков, желающих присоединиться к SWIFT, возросло до 586. Ежедневно сообщество передавало 450 тысяч электронных сообщений.
На сегодняшний день в составе SWIFT находятся более 7 тысяч финансовых организаций и банков, которые находятся в 190 странах. Несмотря на достаточно большое расстояние друг от друга (иногда возникает необходимость передачи информации из США в Австралию), они могут беспрепятственно обмениваться сообщениями и круглосуточно взаимодействовать.
Схема работы SWIFT
Существует два типа сообщений: финансовые (передающиеся между пользователями системы) и системные (передающиеся между пользователями и системой).
Все сообщения системы SWIFT включают в себя:
Преимущества и недостатки SWIFT
На сегодняшний день в России SWIFT уступает в популярности таким известным системам переводов как, например, Western Union или «Юнистрим», однако для оплаты зарубежных услуг или перевода крупной суммы денег в другую страну является, по сути, самым рациональным решением (особенно для тех, у кого возникает постоянная необходимость отправки немалых денежных переводов за границу).
Невероятная масштабность распространения SWIFT в мире позволяет осуществить перевод на клиентский счет любого известного банка, при этом сумма ограничивается только допустимыми величинами, которые не нарушают экономическое законодательство того или иного государства.
SWIFT-переводы отправляют финансовые средства не на ФИО получателя, а на определенные счета, при этом у вас всегда имеется возможность самому выбрать валюту перевода. Также система максимально конфиденциальна и безопасна. При переводе денег через SWIFT, комиссия всегда составляет определенную (фиксированную!) сумму, которая будет увеличиваться в минимальной пропорции от суммы переводов, что будет выгодным при переводе больших сумм денег за рубеж.
Итак, основные преимущества SWIFT заключаются в:
Более того, система зависит от развития корреспондентских отношений банка, посредством которого вами осуществляется перевод (ведь один денежный перевод в SWIFT может осуществляться несколькими финансовыми организациями или банками). Помимо этого, стоимость перевода может повысить наличие банков-посредников, которые возникают тогда, когда валюта перевода отличается от национальной валюты государства, в которое данный перевод осуществляется.
Итак, основные недостатки SWIFT заключаются в:
Что такое SWIFT-код и где он используется?
SWIFT-кодом называют уникальный идентификационный код определенного банка или любого другого участника финансовых расчетов, использующегося при переводе денежных средств из одного государства в другое между банками (которые являются участниками системы SWIFT). Код формируется по следующему стандарту: ISO 9362 (ISO 9362 — BIC).
SWIFT-коды банков обычно можно найти на сайте самого банка (раздел «реквизиты» или «переводы). Вы также можете воспользоваться специальными справочниками SWIFT-кодов банков.
Стоит отметить, что данный код используется только на мировом рынке. Для проведения банковских операций внутринационального характера нужны другие коды. Идентификационная система банков Российской Федерации называется «БИК». В Великобритании, например, это «Sort Code». Безусловно, можно перечислить такие системы всех стран мира, но гораздо легче будет воспользоваться соответствующими справочниками.
Не стоит забывать, что участие в идентификационной системе SWIFT носит исключительно добровольный характер, поэтому отсутствие подключения к ней будет означать, всего лишь, замедление процесса международных банковских операций. Также SWIFT-код гарантирует полную безопасность того или иного перевода, таким образом, риск того, что перевод затеряется между банками, сводится к минимуму.