Интервью — 10 вопросов про Swift. Часть 2
До запуска курса «iOS-разработчик» остается все меньше времени, поэтому сегодня мы продолжаем публиковать материал из серии «10 вопросов про Swift». Первую часть которого можно прочитать тут.
Объясните дженерики в Swift?
Дженерики (универсальные шаблоны) позволяют вам писать гибкие, многократно используемые функции и типы, которые могут работать с любым типом. Вы можете написать код, который избегает дублирования и выражает свое предназначение в ясной, абстрактной манере.
Типы Array и Dictionary в Swift являются универсальными коллекциями (дженериками).
В приведенном ниже коде универсальная функция для свапа двух значений используется для строки и целого числа. Это пример кода многократного использования.
Что такое опциональные типы в swift и когда их следует использовать?
Опциональным (Optional, “опционал”) в Swift является тип, в котором значение может быть, а может и не быть. Опционалы обозначаются путем добавления «?» к любому типу.
Варианты использования опционала:
Свойство, которое может присутствовать или отсутствовать, например отчество или муж/жена в классе Person.
Метод, который может возвращать либо значение, либо ничего, например, поиск соответствия в массиве.
Метод, который может вернуть либо результат, либо получить ошибку и ничего не вернуть, например, пытаться прочитать содержимое файла (в результате чего обычно будут возвращены данные файла), но файл не существует.
Свойства-делегаты, которые не всегда должны быть установлены и обычно устанавливаются после инициализации.
Как слабые ссылки в классах. То, на что они указывают, может быть установлено в nil в любое время.
Если вам нужен способ узнать, когда установлено значение (данные еще не загружены> данные) вместо использования отдельного логической переменной dataLoaded.
Что такое опциональная последовательность (optional chaining) в Swift?
Процессы запроса, вызова свойств, сабскриптов и методов для опционала, который может иметь значение «nil», определяется как опциональная последовательность (опциональная цепочка).
Что такое принудительная распаковка (forced unwrapping)?
Принудительная распаковка — это способ извлечения значения, содержащегося в опционале. Эта операция опасна, потому что вы, по сути, говорите компилятору: я уверен, что этот опционал содержит реальное значение, извлеки его!
Что такое неявная распаковка (implicit unwrapping)?
Неявная распаковка: когда мы определяем неявно распакованный опционал, мы определяем контейнер, который будет автоматически выполнять принудительную распаковку каждый раз, когда мы его считываем.
Если неявно распакованный опционал равен nil и вы пытаетесь получить доступ к его упакованному значению, вы вызовете ошибку времени выполнения. Результат точно такой же, как если бы вы поместили восклицательный знак после обычного опционала, который не содержит значения.
Что такое опциональный биндинг (Optional binding)?
Вы можете распаковывать опционалы как «безопасным», так и «небезопасным» способом. Безопасный способ — использовать опциональный биндинг.
Опциональный биндинг используется для выяснения, содержит ли опционал значение, и если да, то мы сделаем это значение доступным в качестве временной константы или переменной. Таким образом нет необходимости использовать суффикс! для доступа к его значению.
Что такое Guard и каковы его преимущества?
Оператор guard прост и могуч. Он проверяет некоторое условие и, если оно оценивается как ложное, выполняется оператор else, который обычно завершает работу метода.
Пожалуйста, обратитесь к этой статье за дополнительной информацией.
Оператор defer используют для выполнения набора операторов непосредственно перед тем, как выполнение кода покидает текущий блок.
Оператор defer внутри блока if будет выполняться первым. Затем следует шаблон LIFO для выполнения остальных defer операторов.
Перечислите, какие операторы передачи управления используются в Swift?
break — оператор break немедленно завершает выполнение всего оператора потока управления.
continue — оператор continue указывает циклу прекратить то, что он делает, и начать заново в начале следующей итерации цикла.
return — возвращает значения из функций.
throw — нужен проброса ошибок с использованием Throwing Functions
fallthrough — оператор fallthrough используется в блоке switch case для выполнения оператора case, который находится рядом с соответствующими операторами case на основе пользовательских требований.
В swift оператор fallthrough используется для выполнения следующего case, даже если он не совпадает с исходным.
Конец второй части. Первую часть можно прочитать тут.
Ждем ваши комментарии и напоминаем о том, что уже через несколько часов пройдет день открытых дверей, в рамках которого будет подробно рассказано о нашем курсе.
Как использовать дженерики в Swift
Обобщения позволяют вам объявить переменную, которая при исполнении может быть назначена набору типов, определенных нами.
В Swift массив может содержать данные любого типа. Если нам нужен массив целых чисел, строк или чисел с плавающей точкой, мы можем создать его с помощью стандартной библиотеки Swift. Тип, который должен содержать массив, определяется при его объявлении. Массивы являются распространенным примером использования обобщений. Если бы вы реализовали свою собственную коллекцию, вы бы наверняка захотели использовать дженерики.
Давайте рассмотрим дженерики и какие замечательные вещи они позволяют нам делать.
1. Общие функции
Мы начинаем с создания простой универсальной функции. Наша цель — создать функцию для проверки того, что любые два объекта имеют одинаковый тип. Если они одного типа, тогда мы сделаем значение второго объекта равным значению первого объекта. Если они не одного типа, мы напечатаем «не одного типа». Вот попытка реализации такой функции в Swift.
В мире без дженериков мы сталкиваемся с серьезной проблемой. В определении функции нам нужно указать тип каждого аргумента. В результате, если мы хотим, чтобы наша функция работала со всеми возможными типами, нам нужно было бы написать определение нашей функции с различными параметрами для каждой возможной комбинации типов. Это не жизнеспособный вариант.
Мы можем избежать этой проблемы, используя дженерики. Посмотрите на следующий пример, в котором мы используем дженерики.
Здесь мы видим синтаксис использования дженериков. Общие типы обозначены символами T и E Типы указываются путем помещения в определение нашей функции после имени функции. Думайте о T и E как о заполнителях для любого типа, с которым мы используем нашу функцию.
Однако есть серьезная проблема с этой функцией. Это не скомпилируется. Компилятор сгенерирует ошибку, указывающую, что T не конвертируется в E Обобщения предполагают, что, поскольку T и E имеют разные метки, они также будут разных типов. Это хорошо, мы все еще можем достичь нашей цели с помощью двух определений нашей функции.
Есть два случая для аргументов нашей функции:
Мы сократили наши определения функций с потенциально бесконечного числа комбинаций типов аргументов до двух. Наша функция теперь работает с любой комбинацией типов в качестве аргументов.
Общее программирование также может применяться к классам и структурам. Давайте посмотрим, как это работает.
2. Общие классы и структуры
Рассмотрим ситуацию, когда мы хотели бы создать наш собственный тип данных, двоичное дерево. Если мы используем традиционный подход, в котором мы не используем дженерики, то мы будем создавать двоичное дерево, которое может содержать только один тип данных. К счастью, у нас есть дженерики.
Бинарное дерево состоит из узлов, которые имеют:
Каждое двоичное дерево имеет головной узел, у которого нет родителей. Двое детей обычно различаются как левый и правый узлы.
Любые данные в левом дочернем элементе должны быть меньше, чем родительский узел. Любые данные в правом дочернем элементе должны быть больше, чем родительский узел.
В этом примере мы создаем двоичное дерево целых чисел. Создать общий класс довольно просто. Все, что нам нужно сделать, это включить общее в объявление и при необходимости ссылаться на него в теле.
3. Протоколы и ограничения
Во многих ситуациях нам приходится манипулировать массивами для достижения программной цели. Это может быть сортировка, поиск и т. Д. Мы рассмотрим, как генерики могут помочь нам в поиске.
Основная причина, по которой мы используем универсальную функцию для поиска, заключается в том, что мы хотим иметь возможность поиска в массиве независимо от того, какой тип объектов он содержит.
4. Определение протоколов
Давайте рассмотрим пример игры, чтобы продемонстрировать ограничения и протоколы в действии. В любой игре у нас будет ряд объектов, которые нужно со временем обновлять. Это обновление может касаться положения объекта, состояния здоровья и т. Д. А пока давайте воспользуемся примером состояния объекта.
В нашей реализации игры у нас было много различных объектов со здоровьем, которые могли бы быть врагами, союзниками, нейтральными и т. Д. Они не все были бы того же класса, поскольку все наши различные объекты могли бы иметь разные функции.
Мы бы хотели создать функцию с именем check(_:) проверить состояние данного объекта и обновить его текущее состояние. В зависимости от состояния объекта мы можем вносить изменения в его здоровье. Мы хотим, чтобы эта функция работала со всеми объектами независимо от их типа. Это означает, что нам нужно сделать check(_:) универсальная функция. Таким образом, мы можем перебирать различные объекты и вызывать check(_:) для каждого объекта.
Сила дженериков в Swift. Часть 2
Добрый день, друзья. Специально для студентов курса «iOS Разработчик. Продвинутый курс» мы подготовили перевод второй части статьи «Сила дженериков в Swift».
Связанные типы, условия where, сабскрипты и прочее…
В статье «Сила дженериков в Swift. Часть 1» описывались generic-функции, generic-типы и ограничения типа. Если вы новичок, я бы рекомендовала вам для лучшего понимания сначала прочитать первую часть.
Мы можем определить протокол для стека, который мы создали в первой части.
Протокол Stackable определяет необходимый функционал, который должен обеспечивать любой стек.
Давайте изменим наш стек в соответствии с протоколом:
Расширение существующего типа для указания связанного типа
Вы можете расширить существующий тип, чтобы обеспечить соответствие протоколу.
Добавление ограничений в связанный тип:
Рекурсивные ограничения протокола:
Протокол может являться частью собственных требований.
Suffix имеет два ограничения: он должен соответствовать протоколу SuffixableContainer (здесь определяется протокол), а его тип Item должен совпадать с типом Item контейнера.
В стандартной библиотеке Swift в Protocol Sequence есть хороший пример, иллюстрирующий эту тему.
Расширения Generic-типа:
Когда вы расширяете generic-тип, вы не описываете список параметров типа при определении расширения. Вместо этого список параметров типа из исходного определения доступен в теле расширения, а имена параметров исходного типа используются для ссылки на параметры типа из исходного определения.
Generic-условие where
Расширения с Generic-условиями where
Расширение добавляет метод isTop (_ 🙂 только тогда, когда элементы в стеке поддерживают Equatable. Также вы можете использовать generic-условие where с расширениями протокола. К условию where можно добавить несколько требований, разделив их запятой.
Связанные типы с Generic-условием where:
Вы можете включить generic-условие where в связанный тип.
Дженерик алиасы типов:
Алиас типов может иметь общие параметры. Он все еще будет оставаться псевдонимом (то есть он не будет вводить новый тип).
В данном механизме нельзя использовать дополнительные ограничения к параметрам типа.
Такой код не заработает:
Generic-сабскрипты
Специализация дженериков
Специализируя generic-функцию для этих типов, мы можем исключить затраты на виртуальную диспетчеризацию, инлайн вызовы, когда это необходимо, и устранить накладные расходы дженерик системы.
Перегрузка оператора
Generic-типы по умолчанию не работают с операторами, для этого вам нужен протокол.
Интересная вещь о дженериках
Почему вы не можете определить статическое хранимое свойство для универсального типа?
Это потребует отдельного хранения свойств для каждой отдельной специализации дженерика (T).
Использование дженериков в Swift
Если Вы уже разобрались, как программировать на Swift, тогда Вы наверняка уже знаете основы языка Swift и как писать классы и структуры. Но Swift — больше, чем это — намного больше. Задача этой статьи расскажать о очень сильной стороне языка Swift, которая уже успела стать популярной в нескольких других языках под названием дженерики.
С помощью языка программирования безопасного по отношению к типам, это обычная проблема как написание кода, который действует только на один тип, но вполне корректен и для другого типа. Представьте себе, например, что функция добавляет два целых числа. Функция, которая добавляет два числа с плавающей запятой, выглядела бы очень похожей — но фактически, она будет выглядеть идентично.
Единственным отличием будет тип значения переменных.
В языке со строгим контролем типов Вы должны были бы определить отдельные функции как addInts, addFloats, addDoubles, и т.д., где у каждой функции был правильный аргумент, и типы возвращаемых значений.
Много языков программирования осуществляют решения этой проблемы. C++, например, использует шаблоны. Swift, как Java и C # используют дженерики — отсюда и тема этого урока!
В этой статье об обобщённом программировании Swift, Вы нырнете в мир существующих дженериков на языке программирования, в том числе и тех которых Вы уже видели. Тогда, создавайте программу для поиска фотографий в Flickr с пользовательской универсальной структурой данных для отслеживания критерия поиска пользователя.
Примечание: Эта статья о функциональном программировании Swift предназначен для тех, кто уже знает основы Swift. Если Вы плохо знакомы с основами языка Swift, мы рекомендуем Вам сначала посмотреть некоторые наши другие уроки о языке Swift.
Введение в дженерики
Вы не могли бы знать это, но Вы, вероятно, уже видели Дженерики в работе в Swift. Массивы и словари — классические примеры безопасности дженериков в деле.
Разработчики Objective-C привыкли к массивам и словарям, содержащие объекты разных типов в той же самой коллекции. Это обеспечивает большую гибкость, но знаете ли вы, что массив возвращенный из API предназначен для хранения? Вы можете убедиться, посмотрев на документацию или на имена переменных, другая форма документации. Даже в случае с документацией, не существует никаких способов (кроме кода без ошибок!), чтобы предотвратить сбои в коллекции во время выполнения.
С другой стороны Swift, имеет массивы и словари. Массив Ints может содержать только Ints и никогда не может (например) содержат String. Это означает, что Вы можете зарегистрировать код путем написания кода, что позволяет компилятору произвести проверку типов для вас.
Например, в Objective-C UIKit, метод, который обрабатывает прикосновение с учетом пользовательского представления, выглядит следующим образом:
Набор в этом методе, как известно, содержит только экземпляры UITouch, но только потому, что так сказано в документации. Но ничто не мешает объектам быть чем-то еще, и Вы обычно должны вычислить прикосновение в наборе как экземпляры UITouch, чтобы эффективно рассмотреть их как объекты UITouch.
В это время Swift не имеет набора, который определяется в стандартной библиотеке. Тем не менее, если вы использовали массив вместо набора, то вы могли бы написать вышеупомянутый метод следующим образом:
Это свидетельствует о том, что массив touches содержит только UITouch экземпляры, и компилятор выдаст ошибку, если код, обращаясь к этому методу, попытается передать что-либо еще. Мало того, что типы устанавливает/определяет компилятор, то Вам больше не нужно вычислять элементы экземпляров UITouch!
В целом, дженерики обеспечивают типы в качестве параметра класса. Все массивы действуют одинаково, храня значения в виде списка, но общие массивы параметризуют тип значения. Вы могли бы счесть это полезным, если это было так: Алгоритмы, которые вы будете использовать в массивах, не являются нетипоспецифическими, так что все массивы, со всеми типами значений, могут их разделить.
Теперь, когда у Вас есть основные сведения о дженериках и их пользе, Вы спокойно можете применить их к конкретному сценарию.
Как работают Дженерики
Чтобы проверить дженерики, Вы должны создать приложение, которое ищет изображения в Flickr.
Начните с загрузки стартового проекта для этого урока. Откройте его и быстро ознакомиться с основными классами. Класс Flickr может обрабатывать к API Flickr. Обратите внимание, ключ для API который находится в этом классе – предоставляется сразу, но Вы можете использовать свой собственный в случае, если вы хотите расширить приложение. Вы можете подписаться на один из них здесь.
Скомпилируйте и запустите приложение, и Вы увидите это:
Не очень все же! Не бойтесь, картинки с кошечьками скоро появятся.
Ваше приложение будет загружать изображения для каждого пользовательского запроса, и самые последний поиск будут отображать в виде списка в верхней части экрана.
Но что, если Ваш пользователь ищет тот же самый элемент дважды? Было бы хорошо, если бы приложение перенесло старые результаты в верхнюю часть нового списка и заменило его новым результатом.
Вы можете использовать массив для структуры данных чтобы вернуть результат, но в целях изучения дженериков, Вам нужно создать новую коллекцию: упорядоченный словарь.
Во многих языках программирования и фреймворках (включая Swift) наборы и словари не гарантируют какой-нибудь порядок, в отличие от массивов. Упорядоченный словарь выглядит как обычный словарь, но содержит ключи в определенном порядке. Вы будете использовать эту функциональность для хранения результатов поиска, что позволяет быстро найти результаты, а также поддерживать в порядке таблицу.
Если Вы были неосмотрительными, можно создать структуру пользовательских данных, чтобы обработать упорядоченный словарь. Но Вы дальновидны! Вы хотите создать что-то, что Вы можете использовать в приложениях в течение многих последующих лет! Дженерики — это идеальный вариант.
Структура первичных данных
Добавьте новый файл, выбрав File\New\File… и далее iOS\Source\Swift File. Нажмите на Next и назовите файл OrderedDictionary. Наконец, нажмите на Create.
В результате чего у вас будет пустой файл Swift и нужно будет добавить следующий код:
Пока в этом нет ничего удивительного. Объект станет структурой, потому что он должен иметь семантику значений.
Примечание: Одним словом, семантика значений — это необычный способ сказать “скопировать/вставить”, а не “публичная ссылка”. Семантика значений дает много преимуществ, например, нет необходимости беспокоиться о другой части кода, который может неожиданно изменить ваши данные. Чтобы узнать больше, перейдите на Главу 3 как понять Swift с помощью уроков, “Классы и Структуры”.
Теперь Вы должны сделать его дженериком, таким образом, он сможет содержать любой тип значений, которые Вы хотите. Измените определение структуры на следующее:
Элементы в угловых скобках являются параметрами типа дженерика. KeyType и ValueType не являются типами сами по себе, а становятся параметрами, которые можно использовать вместо типов в пределах определения структуры. Если вам не понятно, то все станет ясно в ближайшее время.
Самый простой способ реализовать упорядоченный словарь является поддержание, как массивов, так и словарей. Словарь будет хранить преобразование данных, а массив ключи.
Добавьте следующий код в определение структуры:
Это свидетельствует о двух свойствах, как описано, а также о двух псевдонимах типа, которые дают новое имя существующему типу. Здесь Вы соответственно даете псевдонимы массивам и типам словарей для резервных массивов и словарей. Псевдонимы типа — это отличный способ взять сложный тип и дать ему намного более короткое имя.
Обратите внимание, Вы можете использовать параметры типов KeyType и ValueType из определения структуры вместо типов. Массив представляет собой массив KeyTypes. Конечно, нет такой типа, как KeyType; вместо этого Swift рассматривает его как любой тип пользователя Упорядоченного словаря во время инстанцирования обобщенного типа.
В этот момент, Вы заметите ошибку компилятора:
Type ‘Keytype’ oes not conform to protocol ‘Hashable’
Это могло бы быть сюрпризом для вас. Взгляните на реализацию Dictionary:
Это очень похоже на определения OrderedDictionary, за исключением одной вещи — “: Hashable” после KeyType. Hashable после точки с запятой показывает, что тип, переданный для KeyType, должен соответствовать протоколу Hashable. Это вызвано тем, что Dictionary должен уметь хешировать ключи для своей реализации.
Ограничить обобщенные параметры типа таким образом стало очень распространенно. Например, Вы могли бы ограничить тип значения, чтобы соответствовать протоколам Equatable или Printable в зависимости от того, что Ваше приложение должно сделать с теми значениями.
Откройте OrderedDictionary.swift и замените ваше определение структуры следующим:
Это показывает, что KeyType для OrderedDictionary должен соответствовать Hashable. Это означает, что независимо от того каким типом становится KeyType, он все же будет приемлемым в качестве ключа для основного словаря.
Теперь файл будет компилироваться без ошибок!
Ключи, значения и все такое прочее
Какая польза от словаря, если Вы не можете добавить значения к нему? Откройте OrderedDictionary.swift и добавьте следующую функцию в ваше определение структуры:
Все это ознакомит Вас с более новыми сведениями. Давайте рассмотрим их шаг за шагом:
Теперь, когда у Вас есть возможность добавлять значения в словарь, что относительно того, чтобы удалить значения?
Добавьте следующую функцию к определению структуры в OrderedDictionary:
Давайте рассмотрим еще раз код шаг за шагом:
Доступ к значениям
Вы можете теперь записывать в словарь, но Вы не можете читать из него — это бесполезно для структуры данных! Теперь Вам нужно добавить методы, которые позволят Вам получать значения из словаря.
Откройте OrderedDictionary.swift и добавьте следующий код к структуре определения, и укажите под array и объявлениями переменной dictionary:
Это — вычисляемое свойство для количества упорядоченного словаря, обычно необходимых данных для такой структуры данных. Количество в массиве будет всегда соответствовать количеству упорядоченного словаря, таким образом, все будет просто
Затем, Вам нужно получить доступ к элементам словаря. В Swift, Вы получите доступ к словарю, используя синтаксис индекса, следующим образом:
Теперь Вы уже знакомы с синтаксисом, но вероятно только видели, что он использовался для массивов и словарей. Как же Вы бы использовали Ваши собственные классы и структуры? Swift, к счастью, позволяет легко добавить поведение индекса к пользовательским классам.
Добавьте следующий код в нижнюю часть определения структуры:
Вот, что делает этот код:
Теперь Вы можете индексировать в упорядоченный словарь, как будто это был обычный словарь. Вы можете получить значение для определенного ключа, но что относительно того, чтобы получить доступ с помощью индекса, как с массивом? Видя как это – работает с упорядоченным словарем, было бы неплохо также получить доступ к элементу через индекс.
Классы и структуры могут иметь несколько индексных определений для различных типов аргументов. Добавьте следующую функцию в нижнюю часть определения структуры:
Это подобно нижнему индексу, который Вы добавили ранее, за исключением того, что тип параметра — теперь Int, потому что, это то, что вы используете для ссылки на индекс массива. На сей раз, однако, тип результата — кортеж ключа и значения, потому что, именно Ваш OrderedDictionary хранит заданный индекс.
Как работает этот код:
Задание: Реализуйте сеттер для этого индекса. Добавьте набор с последующим завершением, как и в предыдущем определении индекса.
В этот момент, вы можете задаться вопросом, что произойдет, если KeyType является Int. Преимуществом дженериков является ввод любого хешового типа в качестве ключа, в том числе и Int. В этом случае, как же индекс знает, какой индекс код нужно использовать?
Вот где вам нужно будет дать больше информации о типе для компилятора, чтобы он знал, что ему делать. Обратите внимание, что каждый из индексов имеет другой тип возврата. Поэтому, если вы пытаетесь задать кортеж значения ключа, компилятор будет знать, что он должен использовать нижний индекс на подобии массива.
Давайте запустим программу так, чтобы Вы могли поэкспериментировать с тем, как выполнять компиляцию, какой метод индекса использовать, и как Ваш OrderedDictionary работает в целом.
Создайте новый Playground, нажав на File\New\File…, выбрав iOS\Source\Playground и нажмите Next. Назовите его ODPlayground и затем нажмите Create.
Скопируйте и вставьте OrderedDictionary.swift в новый playground. Вы должны сделать это, потому что, к сожалению, на момент написания этого урока площадка не может «видеть» код в Вашем модуле приложения.
Примечание: Существует обходное решение для этого, кроме как метода скопировать/вставить, который здесь осуществляется. Если Вы переместили код своего приложения в фреймворк, то ваш Playground может получить доступ к вашему коду, как указывает Корин Крич.
Теперь добавьте следующий код в playground:
На боковой панели (или через View\Assistant Editor\Show Assistant Editor) можно увидеть выходную переменную println():
В этом примере, словарь имеет ключ Int, так как компилятор будет рассматривать тип переменной, которая определит, какой индекс нужно использовать. Так как byIndex является (Int, String) tuple, компилятор знает, что нужно использовать индексную версию стиля массива нижнего индекса, которая соответствует ожидаемому типу возвращаемого значения.
Попытайтесь удалить определение типа данных из одной переменной byIndex или byKey. Вы увидите ошибку компилятора, что свидетельствует о том, что компилятор не знает какой нижний индекс нужно использовать.
Подсказка: Чтобы запустить выведения типа, компилятор требует, чтобы тип выражения был однозначен. Когда несколько методов существует с теми же типами аргументов, но с разными типами возвращаемых, то вызывающая функция должна быть конкретной. Добавление метода в Swift может внести в сборку критические изменения, так что будьте внимательны!
Поэкспериментируйте с упорядоченным словарем в playground, чтобы понять, как это работает. Попробуйте добавиться к нему, удалиться из него и изменить ключ и значение типов, прежде чем вернуться в приложение.
Теперь Вы можете читать и писать в свой упорядоченный словарь! Это поможет заботиться о вашей структуре данных. Теперь Вы можете начинать работать с приложением!
Добавление поиска изображения
Пора вернуться назад к приложению.
Откройте MasterViewController.swift добавьте следующее переменное определение, чуть ниже двух @IBOutlets:
Это должен быть упорядоченный словарь, который содержит результат поиска, которые пользователь получил от Flickr. Как Вы можете видеть, он отображает String, критерий поиска, массив Flickr.Photo, или фотографии, возвращенные из API Flickr. Обратите внимание, Вы направляете ключ и значение в угловые скобки так же, как и для обычного словаря. Они становятся параметрами типа KeyType и ValueType в этой реализации.
Вы можете задаться вопросом, почему тип Flickr.Photo имеет период. Это потому, что фотография является классом, который определяется внутри класса Flickr. Эта иерархия является довольно полезной функцией Swiftа, помогая содержать пространство имен, сохраняя имена классов короткими. Внутри класса Flickr, вы можете использовать одну только Photo, которая относятся к классу фото, потому что контекст сообщает компилятору, что это такое.
Затем, найдите метод источника данных табличного представления под названием tableView(_:numberOfRowsInSection:) и измените его на следующий код:
Этот метод теперь использует упорядоченный словарь, который указывает, сколько ячеек имеет наша таблица.
Затем, найдите метод источника данных табличного представления tableView (_:cellForRowAtIndexPath:) и измените его на:
Вот что вы делаете в этом методе:
А теперь поговорим о «начинке». Найдите расширение UISearchBarDelegate и измените единственный метод следующим образом:
Этот метод вызывается тогда, когда пользователь нажимает на кнопку Поиск. Вот то, что делается в этом методе:
Йе-еху-у! Теперь ваше приложение будет искать изображения!
Скомпилируйте и запустите приложение и сделайте несколько поисков. Вы увидите нечто вроде этого:
Теперь повторите один из поисков, которые находятся не вверху списка. И вы увидите, как он возвратиться в начало списка:
Нажали на один из поисков и заметите, что он не показывает фотографий. Пора это исправить!
Дайте мне фотографии!
Откройте MasterViewController.swift и найдите метод prepareForSegue. И замените его на:
При этом используется тот же метод searches упорядоченному словарю, как и при создании ячеек. Он не использует ключ (поиск по ключевому слову), тем не менее, таким образом, вы укажите тем самим, подчеркнувши, что эта часть tuple не должна быть связана с локальной переменной.
Скомпилируйте и запустите приложение, сделайте поиск, а затем нажмите на него. Вы увидите нечто вроде этого:
Кошкииии! Разве Вам не хочется помурлыкать вместо них от такого удовольствия?
Примите мои поздравление, Вы узнали много нового о дженериках! Кроме того, Вы узнали о других интересных вещах, как индексирование, структуры, предусловие, и многое другое.
Если Вы хотите узнать больше о Дженериках, вам нужно посмотреть полную главу учебного пособия о Swift.
Я надеюсь, что Вы сможете использовать всю силу дженериков у Ваших будущих приложениях, чтобы избежать дублирования кода и оптимизировать код для многократного использования. Если у Вас есть какие-либо вопросы или комментарии, пожалуйста, присоединяйтесь к обсуждению на форуме!



