Каталог расширений

Популярные теги

3gp       avi       fb2       jpg       mp3       pdf      

Как сделать свифт файл


Генерация SWIFT-файлов - РЦПП

Платежи. Оплата банковской картой онлайн

Наш сайт подключен к интернет-эквайрингу, и Вы можете оплатить Услугу банковской картой Visa или Mastercard. После подтверждения выбранного Товара либо услуги откроется защищенное окно с платежной страницей процессингового центра CloudPayments, где Вам необходимо ввести данные Вашей банковской карты. Для дополнительной аутентификации держателя карты используется протокол 3-D Secure. Если Ваш Банк-эмитент поддерживает данную технологию, Вы будете перенаправлены на его сервер для прохождения дополнительной идентификации. Информацию о правилах и методах дополнительной идентификации уточняйте в Банке, выдавшем Вам банковскую карту.

Услуга онлайн-оплаты осуществляется в соответствии с правилами Международных платежных систем Visa и MasterCard на принципах соблюдения конфиденциальности и безопасности совершения платежа, для этого используются самые актуальные методы проверки, шифрования и передачи данных по закрытым каналам связи. Ввод данных банковской карты осуществляется в защищенном окне на платежной странице CloudPayments.

В поля на платежной странице требуется ввести номер карты, имя владельца карты, срок действия карты, трёхзначный код безопасности (CVV2 для VISA или CVC2 для MasterCard). Все необходимые данные отображены на поверхности банковской карты.

CVV2/ CVC2 — это трёхзначный код безопасности, находящийся на оборотной стороне карты.

Далее в том же окне откроется страница Вашего банка-эмитента для ввода 3-D Secure кода. В случае, если у вас не настроен статичный 3-D Secure, он будет отправлен на ваш номер телефона посредством SMS. Если 3-D Secure код к Вам не пришел, то следует обратится в ваш банк-эмитент.

3-D Secure — это самая современная технология обеспечения безопасности платежей по картам в сети интернет. Позволяет однозначно идентифицировать подлинность держателя карты, осуществляющего операцию, и максимально снизить риск мошеннических операций по карте.

Гарантии безопасности

Процессинговый центр CloudPayments защищает и обрабатывает данные Вашей банковской карты по стандарту безопасности PCI DSS 3.0. Передача информации в платежный шлюз происходит с применением технологии шифрования SSL. Дальнейшая передача информации происходит по закрытым банковским сетям, имеющим наивысший уровень надежности. CloudPayments не передает данные Вашей карты нам и иным третьим лицам. Для дополнительной аутентификации держателя карты используется протокол 3-D Secure.

В случае, если у Вас есть вопросы по совершенному платежу, Вы можете обратиться в службу поддержки клиентов платежного сервиса по электронной почте [email protected].

Безопасность онлайн платежей

Предоставляемая Вами персональная информация (имя, адрес, телефон, e-mail, номер кредитной карты) является конфиденциальной и не подлежит разглашению. Данные Вашей кредитной карты передаются только в зашифрованном виде и не сохраняются на нашем Web-сервере.

Мы рекомендуем вам проверить, что ваш браузер достаточно безопасен для проведения платежей онлайн, на специальной странице.

Безопасность обработки Интернет-платежей гарантирует ТОО «CloudPayments Kazakhstan». Все операции с платежными картами происходят в соответствии с требованиями VISA International, MasterCard и других платежных систем. При передаче информации используются специализированные технологии безопасности карточных онлайн-платежей, обработка данных ведется на безопасном высокотехнологичном сервере процессинговой компании.

Оплата платежными картами безопасна, потому что:

  • Система авторизации гарантирует покупателю, что платежные реквизиты его платежной карты (номер, срок действия, CVV2/CVC2) не попадут в руки мошенников, так как эти данные не хранятся на сервере авторизации и не могут быть похищены.
  • Покупатель вводит свои платежные данные непосредственно в системе авторизации CloudPayments, а не на сайте интернет-магазина, следовательно, платежные реквизиты карточки покупателя не будут доступны третьим лицам.

Возврат денежных средств

При проведении онлайн-оплаты посредством платежных карт не допускается возврат наличными денежными средствами. Порядок возврата регулируется правилами международных платежных систем:

  1. Потребитель вправе отказаться от товара в любое время до его передачи, после передачи товара отказ необходимо оформить в течение 14 дней;
  2. Возврат товара надлежащего качества возможен в случае, если сохранены его товарный вид, потребительские свойства, а также документ, подтверждающий факт и условия покупки указанного товара;
  3. Потребитель не вправе отказаться от товара надлежащего качества, имеющего индивидуально-определенные свойства, если указанный товар может быть использован исключительно приобретающим его человеком;
  4. При отказе от товара со стороны потребителя продавец должен вернуть ему денежную сумму, уплаченную потребителем, не позднее чем через десять дней со дня предъявления потребителем соответствующего требования.

Для возврата денежных средств на банковскую карту необходимо заполнить «Заявление о возврате денежных средств», которое высылается по требованию компанией на электронный адрес, и оправить его вместе с приложением копии документа, удостоверяющего личность, по адресу [email protected].

Возврат денежных средств будет осуществлен на банковскую карту в течение ___ рабочего дня со дня получения «Заявление о возврате денежных средств» Компанией.

Для возврата денежных средств по операциям, проведенным с ошибками, необходимо обратиться с письменным заявлением и приложением копии документа, удостоверяющего личность, и чеков/квитанций, подтверждающих ошибочное списание. Данное заявление необходимо направить по адресу [email protected].

Сумма возврата будет равняться сумме покупки. Срок рассмотрения Заявления и возврата денежных средств начинает исчисляться с момента получения Компанией Заявления и рассчитывается в рабочих днях без учета праздников/выходных дней.

Случаи отказа в совершении платежа:

  • банковская карта не предназначена для совершения платежей через интернет, о чем можно узнать, обратившись в Ваш Банк-эмитент;
  • недостаточно средств для оплаты на банковской карте. Подробнее о наличии средств на платежной карте Вы можете узнать, обратившись в банк, выпустивший банковскую карту;
  • данные банковской карты введены неверно;
  • истек срок действия банковской карты. Срок действия карты, как правило, указан на лицевой стороне карты (это месяц и год, до которого действительна карта). Подробнее о сроке действия карты Вы можете узнать, обратившись в банк-эмитент.

По вопросам оплаты с помощью банковской карты и иным вопросам, связанным с работой сайта, Вы можете обратиться по следующим телефонам: +7-747-094-71-50, +7-747-094-71-51.

Конфиденциальность

1. Определения

Интернет проект www.rcpp.kz (далее – URL, «мы») серьезно относится к вопросу конфиденциальности информации своих клиентов и посетителей сайта www.rcpp.kz.kz (далее – «вы», «посетители сайта»). Персонифицированной мы называем информацию, содержащую персональные данные (например: ФИО, логин или название компании) посетителя сайта, а также информацию о действиях, совершаемых вами на сайте URL. (например: заказ посетителя сайта с его контактной информацией). Анонимными мы называем данные, которые невозможно однозначно идентифицировать с конкретным посетителем сайта (например: статистика посещаемости сайта).

2. Использование информации

Мы используем персонифицированную информацию конкретного посетителя сайта исключительно для обеспечения ему качественного оказания услуг и их учета. Мы не раскрываем персонифицированных данных одних посетителей сайта URL другим посетителям сайта. Мы никогда не публикуем персонифицированную информацию в открытом доступе и не передаем ее третьим лицам. Исключением являются лишь ситуации, когда предоставление такой информации уполномоченным государственным органам предписано действующим законодательством Республики Казахстан. Мы публикуем и распространяем только отчеты, построенные на основании собранных анонимных данных. При этом отчеты не содержат информацию, по которой было бы возможным идентифицировать персонифицированные данные пользователей услуг. Мы также используем анонимные данные для внутреннего анализа, целью которого является развитие продуктов и услуг URL

3. Ссылки

Сайт www.rcpp.kz может содержать ссылки на другие сайты, не имеющие отношения к нашей компании и принадлежащие третьим лицам. Мы не несем ответственности за точность, полноту и достоверность сведений, размещенных на сайтах третьих лиц, и не берем на себя никаких обязательств по сохранению конфиденциальности информации, оставленной вами на таких сайтах.

4. Ограничение ответственности

Мы делаем все возможное для соблюдения настоящей политики конфиденциальности, однако, мы не можем гарантировать сохранность информации в случае воздействия факторов находящихся вне нашего влияния, результатом действия которых станет раскрытие информации. Сайт www.rcpp.kz и вся размещенная на нем информация представлены по принципу "как есть” без каких-либо гарантий. Мы не несем ответственности за неблагоприятные последствия, а также за любые убытки, причиненные вследствие ограничения доступа к сайту URL или вследствие посещения сайта и использования размещенной на нем информации.

5. Контакты

По вопросам, касающимся настоящей политики, просьба обращаться по адресу [email protected]

Юридическое лицо

ИП "РЕСПУБЛИКАНСКИЙ ЦЕНТР ПОМОЩИ ПРЕДПРИНИМАТЕЛЯМ"

ИИН: 581026302022

ИИК: KZ60826A1KZTD2999743

БИК: ALMNKZKA

Банк: АО "АТФБанк"

Учебник Swift — разработка приложения для iOS8 [Часть 1, Hello World!] / Хабр

Предисловие

Недавно Apple представила общественности достаточно важное изменение в разработке iOS приложений, анонсировав новый язык программирования Swift. Я принял решение: изучая этот язык пошагово, я буду в своих статьях рассказывать обо всём, что мне удалось найти. Это лишь первый пост из многих на эту тему, но я надеюсь, что вы решите изучать язык вместе со мной!

Весьма вероятно, что многие примеры кода, представленные в постах, будут позже изменены. Это отчасти потому, что мой стиль программирования – написать сейчас, чтобы проверить идею, а потом заняться рефакторингом, а также отчасти это потому, что для меня (как и для многих других) Swift – абсолютно новый язык программирования. Так что, скорее всего, как только я узнаю что-нибудь новое, ход этих уроков будет меняться.

Итак, я собираюсь начать с довольно простого приложения. Также я буду объяснять, как работает код. Готовы? Поехали…

UPD: Статья написана в соответствии с изменениями в XСode 6 Beta 5

Основы

Swift отменяет использование стандарта объявления переменных, который использует имя типа перед объявлением переменной, вместо этого для объявления, как и в JavaScript, применяется ключевое слово var.
Так, например, эта строка Objective-C
NSString *myString = @"This is my string."; 

в Swift будет заменена на эту
var myString = "This is my string." 

Для объявления констант используется ключевое слово let
let kSomeConstant = 40 

В данном случае kSomeConstant неявно определяется как целое число. Если же вы хотите конкретизировать тип, то вы можете это сделать так:
let kSomeConstant: Int = 40 

Немножко о Чистом КодеАвтор перевода рекомендует пользоваться вторым примером объявления констант. Довольно показательный пример описан в официальной документации:
let implicitInteger = 70 let implicitDouble = 70.0 let explicitDouble: Double = 70 

В этом автор перевода солидарен с Helecta (см. соответствующий пост)

И массивы, и словари описываются с помощью []
var colorsArray = ["Blue", "Red", "Green", "Yellow"] var colorsDictionary = ["PrimaryColor":"Green", "SecondaryColor":"Red"] 

Это ещё далеко не всё, однако я считаю, что эти основы достаточно важны для дальнейшего чтения учебника. Итак, давайте перейдём к Hello, World!
Hello, World!

В первую очередь, мы напишем самое простое приложение, которое только можно представить, чтобы начать работу — Hello, World!
Наше приложение будет делать только одно: печатать фразу «Hello, World!» в консоль. Для этого нам потребуется установленная IDE XCode, для скачивания которой необходима учётная запись разработчика. Если у вас есть аккаунт, то смело качайте с официального сайта XCode 6 beta 4, желательно это сделать до прочтения ниже описанного.

Итак, вы установили свою копию IDE. Теперь давайте выведем «Hello, World!» на консоль.Этот пример не только демонстрирует простейшее приложение, которое можно написать, но и, что немаловажно, показывает, что среда разработки настроена правильно.
В XCode создайте проект с помощью шаблона приложения с одним видом («Single View Application»).

Убедитесь, что вы выбрали Swift в качестве языка приложения.

Теперь вы должны найти файл AppDelegate.swift в иерархии проекта. Внутри найдите следующую строку:
"// Override point for customization after application launch." 

Замените эту строку на наш изумительный код:
println("Hello World") 


Теперь нажмите «Run». Вы должны увидеть загрузившееся пустое приложение и слова Hello, World!, напечатанные в консоли, расположенной в нижней части окна XCode. Заметьте, это не будет отображаться в симуляторе iPhone.

Поздравляю! Вы только что написали своё первое приложение на Swift! Правда оно не получит никаких премий, призов, только ваши собственные овации. А теперь, давайте копнём немножко глубже…
Добавление Table View

В этом разделе мы попробуем добавить материал на экран. Откройте в XCode файл Main.storyboard, перенесите из Библиотеки Объектов («Object Library») объект Table View на экран приложения, растяните таблицу так, чтобы она совпала с краями. Затем измените высоту, перетянув верхний край, оставив небольшое пространство сверху (это необходимо для строки состояния). Если вы запустите приложение, то увидите в симуляторе пустую таблицу.

Теперь необходимо создать делегат и источник данных для таблицы. Это легче всего сделать в конструкторе интерфейса. Нажмите клавишу «Command», кликните и перетащите Table View к объекту View Controller в иерархии файла .storyboard, и выберите «источник данных» («data source»). Повторите с опцией «delegate».

Примечание:Я получил целую тонну вопросов о вышесказанном, т.к. многие люди сообщают о том, что у них не устанавливается табличный вид. Поэтому, я записал видео, поясняющее как работает подключение объектов Storyboard в коде. Для просмотра перейдите в полноэкранный режим и выберите опцию 720p, чтобы вы могли заметить всё, что вас интересует. Это будет немного отличаться от интерфейса XCode, но функционально всё работает также.

А теперь давайте углубимся в методы протоколов для табличного представления. Из-за использования UITableViewDataSource и UITableViewDelegate мы должны изменить определение класса.
Откройте файл и замените строку

class ViewController: UIViewController { 

следующей
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate { 

Если вы нажмёте клавишу «Command» и кликните на один из этих протоколов, то увидите «обязательные» функции. Для табличного представления необходимы как минимум эти две:
func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! 

Изменим наш класс View Controller путём добавления этих двух функций:
func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int { return 10 } func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! { let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "MyTestCell") cell.textLabel.text = "Row #\(indexPath.row)" cell.detailTextLabel.text = "Subtitle #\(indexPath.row)" return cell } 

Первый метод возвращает количество строк в разделе. В нашем примере используется «магическое» число 10, однако вместо него, как правило, должна использоваться длинна контроллера массива. Наш же код умышленно упрощён.

Во втором методе происходит чистой воды волшебство. Мы создаём экземпляр класса UITableViewCell(cell), используя стиль ячейки Subtitle. Затем мы присваиваем текстовому значению этой ячейки значение "Row #\(indexPath.row)". В Swift подобным образом происходит встраивание значений переменных в строку без конвертации (таким образом, мы получим строки вида "Row #1", "Row #2")

Детализированная текстовая метка (detailTextLabel) доступна только при использовании класса ячеек Subtitle, который мы используем в данном примере.

При запуске приложения вы увидите восхитительный список ячеек с заголовками и подзаголовками, показывающие номера их строк. Это один из наиболее распространённых способов отображения данных в iOS, вы убедитесь, он вам ещё не раз пригодится. Увидеть полный текст кода вы можете на github.

В следующем посте мы исследуем использование API поиска iTunes для создания приложения, способного искать и отображать альбомы внутри iTunes Store.

Вопрос о дальнейшем переводе

Уважаемые Хабралюди! Если вы прочли этот перевод, помогите автору определиться с будущим цикла.
Для этого всего лишь требуется поучаствовать в опросе.

Создание простого приложения с использованием TableView / Хабр

Во время проведения WWDC 2019, одним из самым больших и захватывающих моментом был анонс релиза SwiftUI. SwiftUI — это совершенно новый фреймворк, который позволяет проектировать и разрабатывать пользовательские интерфейсы с написанием меньшего количества кода, декларативным способом.

В отличие от UIKit, который обычно использовался в сочетании с storyboards, SwiftUI полностью основан на программном коде. Тем не менее, синтаксис очень прост для понимания и проект можно быстро просмотреть с помощью Automatic Preview.

Поскольку SwiftUI использует язык Swift, он позволяет создавать приложения той же сложности с гораздо меньшим количеством кода. Более того, использование SwiftUI автоматически позволяет приложению использовать такие функции, как Dynamic Type, Dark Mode, Localization и Accessibility. Кроме того, он доступен на всех платформах, включая macOS, iOS, iPadOS, watchOS и tvOS. Итак, теперь ваш код пользовательского интерфейса может быть синхронизирован на всех платформах, что дает больше времени для того, чтобы сосредоточиться на второстепенном платформо-зависимом коде.

Об этой статье

Важно, чтобы разработчики узнали, как использовать SwiftUI на более ранних стадиях, поскольку компания Apple в конечном итоге сфокусирует большую часть своего внимания на этом фреймворке. В этой статье мы рассмотрим основы SwiftUI и узнаем, как создавать минимальную навигацию, отображать изображения, текст и списки, посредством создания простого списка контактов, который отобразит всех участников нашей команды. При выборе участника команды, приложение отображает детальную информацию, которая содержит изображение пользователя с его краткой биографией. Давайте начнем!

Запустим Xcode 11. На время написания данной статьи, Xcode 11 все еще находится в бета-версии, поэтому некоторые функции могут работать не так, как ожидалось. В этой статье мы будем использовать Swift 5. Несмотря на то, что продвинутые знания языка Swift не обязательны для данной статьи, все же рекомендуется понимание основ языка.

Примечание редактора: Для предварительного просмотра и взаимодействия с изображениями из Canvas в Xcode, убедитесь, что на Mac установлена MacOS версий 10.15 beta.

Создание нового проекта с использованием SwiftUI


Давайте начнем все сначала, чтобы вы могли сразу увидеть, как запустить приложение SwiftUI. Сначала откройте Xcode и выберите пункт «Create new Xcode project». Для платформы iOS выберите Single View App. Введите название приложению и заполните текстовые поля. Однако следует убедиться, что внизу установлен флажок Use SwiftUI. Если вы не выберите эту опцию, Xcode создаст для вас storyboard файл.

Xcode автоматически создаст для вас файл с именем ContentView.swift, и удивительным будет то, что предварительный просмотр вашего кода, будет отображен с правой стороны, как показано ниже.

Если вы не видите предварительного просмотра, необходимо нажать кнопку Resume в зоне предварительного просмотра. Компиляция проекта займет некоторое время. Будьте терпеливы и дождитесь завершения компиляции.

Теперь давайте посмотрим, как можно изменить эти файлы для создания приложения.

Создание представления в виде списка


Создание представления в виде списка осуществляется в три этапа. Первый — это создание строк в списке. Возможно дизайн похож на UITableView. Для этого необходимо создать ContactRow. Второй этап это передача необходимых данных в список. У меня есть данные, которые уже закодированы, и требуется всего лишь несколько изменений, чтобы связать список с данными. Последний этап — это просто добавление Navigation Bar и встраивание списка в Navigation View. Это довольно просто. Теперь посмотрим, как все это было реализовано в SwiftUI.

Создание списка преподавателей


Во-первых, необходимо создать представление для отображения списка всех участников команды, включая фотографии их профиля и их описание. Посмотрим, как это можно сделать.

Как мы видим, в сгенерированном коде имеется компонент Text со значением «Hello World». В редакторе кода изменим значение кода на «Simon Ng».

struct ContentView: View { var body: some View { Text("Simon Ng") } } 

Если все работает верно, справа вы должны увидеть автоматическое обновление. Это эффект мгновенного просмотра, что мы и ожидали.

Давайте добавим в приложении новый элемент Text. Это будет краткое описание участника. Чтобы в приложении добавить новый элемент интерфейса, необходимо нажать кнопку + в правом верхнем углу. Появится новое окно со списком различных вью. Переместим вью с названием Text и поместим его под первоначальный элемент Text, как показано ниже.

Обратите внимание на код слева:

struct ContentView: View { var body: some View { VStack { Text("Simon Ng") Text("Placeholder") } } } 

Можно заметить, что новый элемент Text был добавлен под Text вью с значением Simon Ng. Отличие состоит в том, что теперь это вью, похоже, обернул представление в нечто, называемое VStack. VStack используется для вертикального стека, и он является заменой Auto Layout в SwiftUI. Если у Вас имеется опыт разработки программного обеспечения для watchOS, вы вероятно знаете, что здесь нет никаких ограничений, более того все элементы помещаются в группы. При вертикальном стеке все вью будут расположены вертикально.

Теперь измените текст «Placeholder» на «Founder of AppCoda»

Далее, давайте добавим изображение слева от этого текста. Так как мы хотим расположить представление горизонтально к существующим представлениям, то имеется необходимость обернуть VStack в HStack. Для этого, выполним ⌘+Click на VStack, а затем выберем Embed in HStack. Посмотрим на это ниже:

Данный код должен выглядеть следующим образом:

struct ContentView: View { var body: some View { HStack { VStack { Text("Simon Ng") Text("Founder of AppCoda") } } } } 

Значительных изменений пока нету, но сейчас мы добавим изображение. Измените код, чтобы он выглядел следующим образом:

struct ContentView: View { var body: some View { HStack { Image(systemName: "photo") VStack { Text("Simon Ng") Text("Founder of AppCoda") } } } } 

Начиная с iOS 13, Apple представляет новую функцию под названием SFSymbols. SF Symbols, разработанный компанией Apple, представляет собой набор из более чем 1500 символов, которые можно использовать в приложениях. Поскольку они могут легко интегрироваться с системным шрифтом San Francisco, символы автоматически обеспечивают оптическое вертикальное выравнивание с текстом любого размера. Поскольку у нас пока нет изображений наших преподавателей, будем использовать так называемый placeholder.

Теперь сосредоточимся на некоторых незначительных проблемах дизайна. Поскольку имеется необходимость эмуляции внешнего вида UITableRow, давайте выровняем текст по левому краю (т. е. сделаем его главным). Для этого выполним ⌘+Click на VStack и нажмем Inspect. Выберем значок выравнивания по левому краю, как показано ниже:

Далее увидим изменение в коде. Также код будет изменен в реальном времени для отображения новых изменений.

VStack(alignment: .leading) { ... } 

Теперь, когда второе текстовое представление является заголовком, давайте изменим шрифт. Как и раньше, ⌘+Click на текстовом представлении «Founder of AppCoda» в режиме предварительного просмотра и выбираем Inspect. Изменим шрифт на «Subheadline» и отобразим предварительный просмотр и изменение кода в реальном времени.

Давайте также изменим цвет и установим его на «Серый». Данный код должен выглядеть следующим образом:

struct ContentView: View { var body: some View { HStack { Image(systemName: "photo") VStack(alignment: .leading) { Text("Simon Ng") Text("Founder of AppCoda") .font(.subheadline) .color(.gray) } } } } 

Теперь, после окончания проектирования ряда сэмплов, мы подошли к волшебной части. Посмотрите, как легко создать список. Выполним ⌘+Click на HStack и выполним клик на Embed in List. Вуаля! Посмотрите, как код будет автоматически меняться, и пустая область будет отображать 5 красивых новых строк, каждая из которых показывает Simon Ng в качестве члена команды.

Также обязательно обратите внимание, как был создан List в коде. Удалив HStack и заменив его повторяющимся List, было создано табличное представление. Теперь подумайте сколько времени вы сэкономили и на сколько меньше кода написали, избегая все эти UITableViewDataSource, UITableViewDelegate, Auto Layout, реализации для Dark Mode и т. д. Все это само по себе показывает мощь и силу SwiftUI. Тем не менее, мы далеки от завершения. Давайте добавим некоторые реальные данные в новый список.

Подключение данных к списку


Данные, которые нам необходимы, это список участников команды и их биография вместе с папкой со всеми их изображениями. Вы можете скачать необходимые файлы здесь. Вы должны найти 2 файла с именами Tutor.swift и Tutor.xcassets.

После загрузки импортируйте файл с расширением Swift и папку ресурсов в проект Xcode. Чтобы их импортировать, просто перетащите их в навигатор проекта.

В файле Tutor.swift объявляем структура Tutor и приводим ее в соответствие с протоколом Identifiable. Вы поймете, почему это важно позже. Также определяем переменные id, name, headline, bio и imageName. Наконец, добавим некоторые тестовые данные, которые будут использоваться в нашем приложении. В Tutor.xcassets имеются изображения всех участников команды.

Вернитесь к ContentView.swift и измените код следующим образом:

struct ContentView: View { //1 var tutors: [Tutor] = [] var body: some View { List(0..<5) { item in Image(systemName: "photo") VStack(alignment: .leading) { Text("Simon Ng") Text("Founder of AppCoda") .font(.subheadline) .color(.gray) } } } } #if DEBUG struct ContentView_Previews : PreviewProvider { static var previews: some View { //2 ContentView(tutors: testData) } } #endif 

Все довольно просто:

  1. Определим новую переменную с именем tutors, которая является пустым массивом структур Tutor.
  2. Поскольку мы определяем новую переменную для структуры ContentView, следовательно необходимо также изменить ContentView_Previews, чтобы отобразить это изменение. Установим в testData параметр tutors.

В предварительном просмотре не будет никаких изменений, потому что мы еще не используем тестовые данные. Чтобы отобразить тестовые данные, измените код следующим образом:
struct ContentView: View { var tutors: [Tutor] = [] var body: some View { List(tutors) { tutor in Image(tutor.imageName) VStack(alignment: .leading) { Text(tutor.name) Text(tutor.headline) .font(.subheadline) .color(.gray) } } } } 

Убедимся, что ContentView использует tutors для отображения данных на экране.

Вот так! Посмотрите, как изменилось представление.

Изображения отображаются в виде квадрата. Хотелось бы, чтобы они выглядели более округлыми. Давайте посмотрим, как мы можем сделать изображение с закругленными углами. В правом верхнем углу нажмите кнопку + и перейдите на вторую вкладку. Так будет отображен список модификаторов макета, которые вы можете добавлять к изображениям.

Ищите «Corner Radius/Угловой радиус», перетащите его из окна предварительного просмотра и поместите его на изображение. Вы должны увидеть измененный код, и изображения предварительного просмотра будет изменено на следующее.

Тем не менее, радиус закругления в 3 слишком мал. Итак, измените его на 40. Таким образом, получаем красивые скругленные картинки.

Ячейка и список готовы! Далее необходимо отображать детальную информацию, когда пользователь нажимает на ячейку. Давайте начнем работу с создания навигаций.

Создание навигации


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

В SwiftUI обернуть List вью в NavigationView также очень просто. Все, что вам нужно сделать, это изменить код следующим образом:

... var body : some View { NavigationView { List(tutors) { tutor in ... } } } ... 

Необходимо выполнить оборачивание кода List в NavigationView. По умолчанию панель навигации не имеет заголовка. Предварительный просмотр должен переместить список вниз, оставляя очень большой разрыв в середине. Это потому, что мы не установили заголовок для панели навигации. Чтобы исправить это, необходимо установить заголовок, добавив следующую строку кода (т.е. .navigationBarTitle ):

... var body : some View { NavigationView { List(tutors) { tutor in ... } .navigationBarTitle(Text("Tutors")) } } ... 

Теперь экран должен выглядеть примерно так:

Далее установим кнопку навигации. NavigationButton ведет на новый экран, который находится в стеке навигации. Подобно тому, как мы обернули List в NavigationView, необходимо обернуть содержимое List с помощью NavigationButton, как показано ниже:

... var body : some View { NavigationView { List(tutors) { tutor in NavigationButton(destination: Text(tutor.name)) { Image(tutor.imageName) VStack(alignment: .leading) { Text(tutor.name) Text(tutor.headline) .font(.subheadline) .color(.gray) } } } .navigationBarTitle(Text("Tutors")) } } ... 

Теперь имя участника команды отображено в подробном представлении. Сейчас самое время проверить это.

В текущем режиме предварительного просмотра вы не можете взаимодействовать с представлением. Обычно, когда вы нажимаете на предварительный просмотр, происходит простое выделение кода. Чтобы выполнить тест и проверить взаимодействие с пользовательским интерфейсом, необходимо нажать кнопку воспроизведения в правом нижнем углу.

Вью станет темным, и возможно, придется подождать пару секунд, пока загрузится весь симулятор, прежде чем появится возможность реально взаимодействовать с представлениями.

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

Прежде чем перейти к реализации детализированного представления, позвольте мне показать вам хитрый прием, который поможет сделать ваш код более разборчивым. ⌘+Click NavigationButton и выберите «Extract Subview».

Бум! Вы можете видеть, что весь код в NavigationButton был создан в совершенно новой структуре, которая делает его очень разборчивым. Переименуйте ExtractedView в TutorCell.

Теперь можно получить ошибку в TutorCell. Это потому, что у нас нет параметра tutor для передачи в эту структуру. Исправить ошибку очень просто. Добавьте новую константу в структуру TutorCell следующим образом:

struct TutorCell: View { let tutor: Tutor var body: some View { ... } } 

А, в ContentView, добавьте отсутствующий параметр изменив строку на:

... List(tutors) { tutor in TutorCell(tutor: tutor) }.navigationBarTitle(Text("Tutors")) ... 

Вот и все! Имеется список и ячейки, все они хорошо продуманные и разложены в требуемом порядке! Далее мы собираемся создать детальный вид, который будет показывать всю информацию о преподавателе.

Создание представления для отображения детальной информаций.


Давайте создадим новый файл, перейдя в File > New > File. Под iOS выберите SwiftUI View и назовите этот файл TutorDetail.

В предварительном просмотре уже создался главный базовый вид. Давайте с ним поработаем. Сначала нажмите на кнопку « +» и поместите изображение над уже встроенным представлением Text. Установите имя изображения «Simon Ng». Должно появится изображение Саймона. Теперь измените код так, как показано ниже:

struct TutorDetail: View { var body: some View { //1 VStack { //2 Image("Simon Ng") .clipShape(Circle()) .overlay( Circle().stroke(Color.orange, lineWidth: 4) ) .shadow(radius: 10) //3 Text("Simon Ng") .font(.title) } } } 

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

  1. Сначала мы упаковываем все наши представления в вертикальный стек. Это имеет решающее значение для макета дизайна, который мы будем принимать.
  2. Затем берем изображение Саймона и оживляем его. Сначала установим клипы изображения в форме круга. Вместо того, чтобы установить cornerRadius, это намного эффективнее, поскольку круг можно приспособить к различным размерам изображения. Мы добавляем наложение круга с белой рамкой, которая обеспечивает красивую оранжевую рамку. Наконец, мы добавим легкую тень, чтобы обеспечить некоторую глубину изображения.
  3. Наша последняя строка кода устанавливает шрифт имени преподавателя на шрифт заголовка.

Также необходимо добавить еще два текстовых вью: headline и bio. Перетащите два текстовых вью ниже текстового вью с именем преподавателя, и отредактируйте их:

struct TutorDetail: View { var body: some View { VStack { Image("Simon Ng") .clipShape(Circle()) .overlay( Circle().stroke(Color.orange, lineWidth: 4) ) .shadow(radius: 10) Text("Simon Ng") .font(.title) Text("Founder of AppCoda") Text("Founder of AppCoda. Author of multiple iOS programming books including Beginning iOS 12 Programming with Swift and Intermediate iOS 12 Programming with Swift. iOS Developer and Blogger.") } } } 

Хорошей новостью является то, что у нас есть текстовые вью. Плохая новость в том, что они плохо выглядят и не показывают разницу между заголовком и детальным описанием. Кроме того, текстовое вью биографии не отображает весь текст. Давайте исправим это.

Обновите код следующим образом:

struct TutorDetail: View { var body: some View { VStack { Image("Simon Ng") .clipShape(Circle()) .overlay( Circle().stroke(Color.orange, lineWidth: 4) ) .shadow(radius: 10) Text("Simon Ng") .font(.title) //1 Text("Founder of AppCoda") .font(.subheadline) //2 Text("Founder of AppCoda. Author of multiple iOS programming books including Beginning iOS 12 Programming with Swift and Intermediate iOS 12 Programming with Swift. iOS Developer and Blogger.") .font(.headline) .multilineTextAlignment(.center) } } } 
  1. Сначала мы устанавливаем “Founder of AppCoda” со шрифтом subheadline.
  2. Точно так же мы устанавливаем текстовое представление биографии используя шрифт headline. Мы также выровняем текст с линией .multilineTextAlignment(.center)

Давайте исправим следующую ошибку. Нам необходимо отобразить весь текст текстового представления биографии. Это можно легко сделать, добавив новую строку кода:

... Text("Founder of AppCoda. Author of multiple iOS programming books including Beginning iOS 12 Programming with Swift and Intermediate iOS 12 Programming with Swift. iOS Developer and Blogger.") .font(.headline) .multilineTextAlignment(.center) .lineLimit(50) ... 

Все выглядит хорошо. Есть одно последнее изменение дизайна, которое я хочу сделать. Заголовок и текстовые представления биографии находятся слишком близко друг к другу. Я хотел бы иметь некоторое пространство между этими двумя представлениями. Кроме того, я хотел бы добавить некоторые отступы ко всем вью, чтобы они не касались краев устройства. Убедитесь, что вы изменили код следующим образом:

struct TutorDetail: View { var body: some View { VStack { Image("Simon Ng") .clipShape(Circle()) .overlay( Circle().stroke(Color.orange, lineWidth: 4) ) .shadow(radius: 10) Text("Simon Ng") .font(.title) Text("Founder of AppCoda") .font(.subheadline) //1 Divider() Text("Founder of AppCoda. Author of multiple iOS programming books including Beginning iOS 12 Programming with Swift and Intermediate iOS 12 Programming with Swift. iOS Developer and Blogger.") .font(.headline) .multilineTextAlignment(.center) .lineLimit(50) //2 }.padding() } } 

Здесь выполним несколько изменений:

  1. Добавить разделитель так же просто, как и вызвать Divider()
  2. Чтобы добавить отступы ко всему вертикальному стеку, необходимо вызвать .padding() в конце объявления VStack.

Это все! Поздравляю! Экран детального просмотра готов. Осталось только соединить наш список преподавателей и их детальное описание. Это довольно просто.

Передача данных


Для передачи данных необходимо объявить некоторые параметры в структуре TutorDetail. Перед объявлением переменной body добавьте следующие переменные:
var name: String var headline: String var bio: String var body: some View { ... } 

Это параметры, которые мы передадим из ContentView. Проведите следующие изменения:

... var body: some View { VStack { // 1 Image(name) .clipShape(Circle()) .overlay( Circle().stroke(Color.orange, lineWidth: 4) ) .shadow(radius: 10) //2 Text(name) .font(.title) //3 Text(headline) .font(.subheadline) Divider() //4 Text(bio) .font(.headline) .multilineTextAlignment(.center) .lineLimit(50) //5 }.padding().navigationBarTitle(Text(name), displayMode: .inline) } ... 
  1. Заменим имя преподавателя для image на переменную name
  2. Заменим текст заголовка на переменную headline
  3. Наконец, заменим длинный абзац текста на переменную bio
  4. Также была добавлена строка кода, которая установит заголовок панели навигации на имя преподавателя.

И последнее, но не менее важное: нам необходимо добавить отсутствующие параметры в структуру TutorDetail_Previews.

#if DEBUG struct TutorDetail_Previews : PreviewProvider { static var previews: some View { TutorDetail(name: "Simon Ng", headline: "Founder of AppCoda", bio: "Founder of AppCoda. Author of multiple iOS programming books including Beginning iOS 12 Programming with Swift and Intermediate iOS 12 Programming with Swift. iOS Developer and Blogger.") } } #endif 

В приведенном выше коде мы добавляем отсутствующие параметры и заполняем информацию той, что имели ранее.

Вы можете быть удивлены, что случилось с инструкциями #if DEBUG/#endif. Это означает, что любой код, заключенный в эти команды, будет выполнен только при предварительном просмотре для целей отладки. В вашем последнем приложении этого не будет.

Ничто не должно измениться, так как информация также неизменна.

И так, последний шаг — связать это представление со списком. Переключитесь на файл ContentView.swift. Все, что необходимо сделать, это изменить одну строку кода в структуре TutorCell. Измените код NavigationButton на ниже приведенный:

... var body: some View { return NavigationButton(destination: TutorDetail(name: tutor.name, headline: tutor.headline, bio: tutor.bio)) { ... } } ... 

Вместо того, чтобы отобразить представление с именем преподавателя, необходимо изменить место назначения на TutorDetail при заполнении соответствующих данных. Данный код должен выглядеть следующим образом:

Нажмите кнопку воспроизведения и выполняйте взаимодействие с представлением. Если все работает хорошо, приложение будет также хорошо работать.

Просто выберите одну из записей участника:

И тогда будут отображены детали участника на детальном экране.

Заключение


В этой статье представлены основы SwiftUI. Теперь будет удобно создавать простые приложения, такие как планировщик задач и т.д. Я предлагаю взглянуть на некоторые из приведенных ниже ресурсов, таких как документация от компании Apple и сессии WWDC 2019, посвященные данному фреймворку.

SwiftUI Documentation
SwiftUI Tutorials
Introducing SwiftUI: Building Your First App
SwiftUI Essentials

Этот фреймворк — это будущее развития Apple, поэтому очень здорово, если вы начнете именно с него. Помните, что если вы не уверены в коде, попробуйте поработать с автоматическим предварительным просмотром и посмотрите, сможете ли вы внести изменения в пользовательский интерфейс напрямую, чтобы увидеть, как создается код. Если у вас есть какие-либо вопросы, не стесняйтесь, задавайте их в комментариях ниже.

Для справки вы можете скачать готовый проект здесь.

1.1. Управление файлами | Swift World

Видео и материалы

Сражаться из страха или злости — значит вести войну без конца.

Император Шаохао

В этом уроке

  • Что такое файловая система?
  • WorkSpace
  • Общий код для iOS и macOS
  • Условная компиляция

Файловая система

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

Даже если Вашему приложению требуется работать с данными, то чаще всего такие манипуляции не будут сильно сложными.

Помните, что стандартные механизмы доступа к файлам предполагают чаще всего запись и считывание целых объектов - операции по нахождению конкретной точки, особенно для нетекстового файла, и вставки туда чего-либо могут быть неэффективны. В будущем мы рассмотрим механизмы, которые помогут нам решить эту проблему иначе.

Для работы с файлами используется тип из Foundation - FileManager (корреспондирующий ссылочный тип NSFileManager). В большинстве случаев Вам не придётся создавать свой собственный объект - будет достаточно воспользоваться стандартным статическим FileManager.default. Плюсом данного подхода будет то, что такой объект заведомо потокобезопасен и Вы можете отправлять ему сообщения из множества потоков одновременно!

Ограничения на взаимодействие с файлами в разных операционных системах различается. Данный урок лучше всего выполнять в консольном приложении для macOS или использовать в каком-нибудь методе viewDidLoad для iOS. Мы будем демонстрировать работу программы на macOS и iOS.

Чтобы иметь возможность демонстрировать работу сразу на двух устройствах, мы создаем workspace - объединение нескольких проектов и сущностей в одном.
Используйте следующий путь для создания рабочего пространства File -> New -> Workspace

В нем создайте два проекта - для iOS и macOS, как Вы это делали ранее, однако на этапе выбора директории выберите Add To и укажите название текущего воркспейса.

Теперь создайте в папке c macOS Swift-файл для нашего класса-обёртки. Мы назвали его FileWrapping.

import Foundation public class FileWrapping { static func doWork() { } }

Теперь добавьте в main.swift вызов данной функции.
Нажмите правой кнопкой по проекту для iOS и выберите Add File to...

Затем пролистайте папки вверх, пока не найдёте файл-обёртку, добавьте его в данный проект. Теперь на него есть ссылка в обоих проектах.

Не используйте данный метод для создания кросс-кода - для этой цели существуют фреймворки, о которых мы поговорим позднее.

Добавьте вызов doWork в метод viewDidLoad нашего единственного контроллера.


Сделаем же уже что-нибудь!

Весь дальнейший код будет писаться нами в теле doWork

Давайте создадим себе небольшую обёртку, дабы сократить количество кода:

let manager = FileManager.default

Давайте попробуем вывести временную директорию для файлов:

print(manager.temporaryDirectory) print(manager.temporaryDirectory.path)

В первом случае мы получаем ссылку URL на директорию, во втором извлекаем путь до неё. Отличие ссылки от пути в том, что ссылка содержит также протокол доступа. В случае для файлов - это file://. URL - крайне универсальный способ работы с данными - он может ссылаться на самые разные ресурсы, не только файлы и сайты. В дальнейшем мы узнаем ещё несколько способов применить этот тип.

Также можно получить путь до текущей рабочей директории:

print(manager.currentDirectoryPath) // /Users/gorloff/Library/Developer/Xcode/DerivedData/final@10@1_1-bdkbrmfqfxwmzfgmrfzjklaurcqo/Build/Products/Debug

Рабочую директорию для приложения-непесочницы можно изменить методом changeCurrentDirectoryPath(_:):

//manager.changeCurrentDirectoryPath("/")

Однако для приложений песочниц это не даст ничего хорошего...

Запустите программу на macOS, симуляторе и реальном устройстве, Вы получите три вывода соответственно:

//macOS //file:///var/folders/6c/b82vsq25317f_9w0g07jf0qr0000gn/T/ //iOS simulator //file:///Users/gorloff/Library/Developer/CoreSimulator/Devices/C4B5A863-9E2D-4DD3-883F-EF5823479DEC/data/Containers/Data/Application/37BF337D-2EAA-4405-A621-177D0A0B2030/tmp/ //iOS real device //file:///private/var/mobile/Containers/Data/Application/F45C522C-22A9-478A-B2ED-39CBE498F307/tmp/

Папка для временных файлов управляется системой:

  1. В случае с macOS она выступает разделяемой,
  2. Для симулятора она находится внутри приложения, но доступна в macOS
  3. Для iOS она находится внутри приложения и по паттерну песочницы недоступна извне

Далее мы можем комментировать все сообщения вывода, чтобы не захламлять консоль.

Для переключения между целями используется то же меню, что и для выбора целевого устройства. Учтите, что если Вы запустите приложение, то теперь команды управления его активностью относятся именно к нему, пока Вы не прекратите выполнение.

Помните, что директория для временных файлов является директорией именно для временных файлов. Не используйте её для хранения долговременных файлов - система не гарантирует и даже не обещает, что файлы в ней будут живы в течение времени, после высвобождения управления ими.

Попробуем получить домашнюю директорию пользователя:

print(manager.homeDirectoryForCurrentUser.path) // "/Users/gorloff"

Это сработает только на macOS, выдав ошибку компиляции на всём остальном. Это связано с тем, что данная часть API Foundation доступна только на macOS. Как же быть, если мы хотим заставить программу работать в случае отсутствия какого-то API на целевой платформе? Мы воспользуемся условными инструкциями компилятора:

#if !targetEnvironment(simulator) print(manager.homeDirectoryForCurrentUser.path) #endif

В отличие от препроцессора в других языках, данная система не обрабатывает исходный код - они работают на этапе компиляции и в рантайме. Указанная директива заставит данный код выполниться для устройств, не являющихся симулятором. Она полезна для создания заглущек для функций, доступных на реальном устройстве, но отсутствующих в симуляторе (камера, реальная геолокация и так далее).

Обратите внимание, что при смене конфигурации для выполнения в верхнем коде меняется и обработка кода. Все конструкции внутри директив компилятора проверяются, даже если никогда не будут выполнены.

Боле правильным будет заменить условие на проверку текущей системы на macOS:

#if os(macOS) print(manager.homeDirectoryForCurrentUser.path) #endif

Есть также метод, позволяющий получить домашнюю директорию пользователя по его имени:

#if os(macOS) print(manager.homeDirectory(forUser: "gorloff")?.path) // Optional("/Users/gorloff") print(manager.homeDirectory(forUser: "Вячеслав Горлов")?.path) // Optional("/Users/gorloff") print(manager.homeDirectory(forUser: "root")?.path) // Optional("/var/root") print(manager.homeDirectory(forUser: "mistress")?.path) // nil #endif

Данный метод возвращает опциональную ссылку, которая может быть нулевой, если пользователя с именем не существует или же его домашняя директория недоступна.

Имя пользователя это не Вячеслав Горлов, хотя macOS и позволяет использовать их взаимозаменяемо. Однако старайтесь использовать истинное латинское имя. Вы можете получить его, запустив терминал


Получение важных директорий

Вы можете получить важные директории для работы использовав метод менеджера url(for:in:appropriateFor:create:):

do { let documentsURL = try manager.url(for: .documentDirectory, in: .allDomainsMask, appropriateFor: nil, create: false) print(documentsURL) } catch { print(error) }
  1. FileManager.SearchPathDirectory - перечисление, содержашее привязки к типовым директориям. Мы получаем здесь директорию для документов. На macOS - это общая папка для пользователя, на iOS - используется каждым приложением отдельно. Её цель - хранение долговременных данных. Объектов данного типа крайне много, чтобы на данном этапе мы не останавливались на них, Вы можете прочесть о них подробнее на сайте документации Apple
  2. FileManager.SearchPathDomainMask - маска домена, в которой идёт поиск директории. Удовлетворяет OptionSet, а значит может быть использованы по-одному или в массиве. Выделяют:
    • userDomainMask - отсчёт идёт от домашней директории пользователя ~
    • localDomainMask - место, откуда объекты доступны всем пользователям системы
    • networkDomainMask - место, откуда ресурсы доступны по сети /Network
    • systemDomainMask - предоставляется Apple и не может быть изменена /System
    • allDomainsMask - все домены вместе
  3. Ссылка, которая добавится к новосозданной директории, если в функцию первым аргументом передаётся .itemReplacementDirectory, то есть запрос на создание временной директории.
  4. Следует ли создать директорию, если она не существует? Игнорируется, если сделан запрос на временную директорию.

Мы обернули вызов в do-catch, так как операция потенциально может выбросить исключение. Заметьте, что если Вы попробуете получить с помощью данного способа домашнюю директорию пользователя на iOS, то программа скомпилируется. Просто будет получено исключение.

Дальнейшая работа будет проходить внутри блока do-catch, чтобы отлавливать возможные ошибки.

Аналогично работает метод urls(for:in:) - он возвращает массив со всеми ссылками на директории по заданному домену (первый метод возвращает лишь первую):

let applicationURLs = manager.urls(for: .applicationDirectory, in: .allDomainsMask) //[file:///Users/gorloff/Applications/, file:///Applications/, file:///Network/Applications/] print(applicationURLs)

Возвращает ссылки на папки с приложениями.



Знакомимся с языком Swift на примере игры Snake

Всем привет! В преддверии запуска курса «iOS-разработчик. Базовый курс» мы организовали очередной открытый урок. Этот вебинар рассчитан на людей, которые имеют опыт разработки на любых языках и платформах, однако желают ещё изучить язык Swift и освоить разработку под iOS. На уроке мы подробно разобрали синтаксис и ключевые конструкции языка Swift, познакомились с основными инструментами разработки.



Участники вебинара узнали:
  • что собой представляет язык Swift, каковы его особенности;
  • как среда разработки XCode помогает в процессе работы;
  • как создать простейшую игру под iOS.

Вебинар провёл Алексей Соболевский, iOS-разработчик в Яндексе.

Делаем Snake своими руками


Для работы мы использовали интегрированную среду разработки Xcode. Это удобная, бесплатная и функциональная среда, созданная компанией Apple.

В самом начале создали новый проект и выбрали базовый набор файлов «Game»:

Не мудрствуя лукаво, назвали проект «Snake». Все настройки оставили по умолчанию, убедившись лишь в том, что в строке Game Technology стоит SpriteKit.

Подробности создания проекта.

После выполнения вышеперечисленных действий в левой части окна отобразится список файлов, автоматически созданных для нашего проекта. Одним из наиболее важных файлов является AppDelegate.swift, который помогает системе связываться с нашим кодом, когда возникают какие-нибудь значимые события для приложения (запуск, пуш, переход по ссылке и т. п.). Код этого файла:

// // AppDelegate.swift // SnakeGame // // Created by Alexey Sobolevsky on 15/09/2019. // Copyright 2019 Alexey Sobolevsky. All rights reserved. // import UIKit @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. return true } }

Не менее важными файлами являются GameScene.swift и GameViewController.swift. Класс GameScene создаёт сцену, а GameViewController отвечает за один экран приложения, который мы видим (один экран — один GameViewController). Конечно, это правило поддерживается не всегда, но в целом оно работает. Так как наше приложение довольно простое, у нас будет всего один GameViewController. С него и начнём.

Пишем GameViewController


Код по умолчанию мы удалим. У вью-контроллера есть несколько методов, которые срабатывают в зависимости от состояния экрана. Например, viewDidLoad() срабатывает, когда все элементы экрана уже загрузились, и экран вот-вот отобразится на смартфоне. Так как у нас игра, мы должны в наш вью-контроллер поместить игровую сцену (именно здесь будет бегать змейка и будут происходить все остальные события игры).

Создаём сцену:

let scene = GameScene(size: view.bounds.size)

let — константа и ключевое слово. В языке Swift используется также и ключевое слово var, необходимое для определения переменной. Используя var, мы можем изменять значение переменных многократно во время работы программы. Используя let, мы не можем изменить значение переменных после инициализации.

Теперь нам надо убедиться, что вью, в которое мы поместим созданную сцену, соответствует нужному типу. Для этого используем конструкцию guard — это то же самое, что if, только наоборот (if not):

guard let skView = view as? SKView else { return }

Убедившись, что элемент экрана соответствует нужному типу, добавляем к нему нашу сцену:
skView.presentScene(scene)

Также нужно, чтобы показывалось количество кадров в секунду (FPS):
skView.showsFPS = true

Потом отобразим количество элементов всех типов на сцене:
 skView.showsNodeCount = true

И сделаем так, чтобы элементы отображались на экране вне зависимости от их порядка в иерархии элементов:
skView.ignoresSiblingOrder = true

А ещё не забываем о том, что наша сцена должна растягиваться на всю ширину экрана:
scene.scaleMode = .resizeFill

Вот итоговый код файла GameViewController.swift:
import UIKit import SpriteKit import GameplayKit class GameViewController: UIViewController { override func viewWillLayoutSubviews() { super.viewWillLayoutSubviews() setup() } private func setup() { guard let skView = view as? SKView else { return } let scene = GameScene(size: view.bounds.size) skView.showsFPS = true skView.showsNodeCount = true skView.ignoresSiblingOrder = true scene.scaleMode = .resizeFill skView.presentScene(scene) } } 

Подробности создания файла GameViewController.swift.

Итак, мы создали сцену, но она пустая, поэтому если запустим эмулятор сейчас, увидим лишь чёрный экран.

Пишем GameScene


Как и в прошлый раз, большую часть кода удаляем, а потом выполняем необходимые настройки сцены. Здесь также есть свои методы. Например, так как мы добавили нашу сцену во ViewController, нам нужен метод didMove():
override func didMove(to view: SKView) { setup(in: view) }

Далее, когда запускается игра, на каждый кадр происходит вызов метода Update():
override func update(_ currentTime: TimeInterval) { snake?.move() }

И ещё нам понадобится несколько обработчиков нажатия на экран:
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { guard let touchedNode = findTouchedNode(with: touches) else { return }
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) { guard let touchedNode = findTouchedNode(with: touches) else { return }

Как известно, Swift славится наличием синтаксического сахара. Синтаксический сахар — это такие технические моменты, которые упрощают жизнь разработчику, ускоряют написание кода. Всё это очень помогает при настройке сцены, которой мы сейчас и займёмся. В первую очередь, зададим цвет:
backgroundColor = SKColor.white

Так как змейка работает в плоскости, физика нам не нужна, и её можно отключить, чтобы змейка не падала вниз из-за гравитации. Также нам не нужно, чтобы игра вращалась и т. п.:
physicsWorld.gravity = .zero physicsWorld.contactDelegate = self physicsBody = SKPhysicsBody(edgeLoopFrom: frame) physicsBody?.allowsRotation = false physicsBody?.categoryBitMask = CollisionCategories.edgeBody physicsBody?.collisionBitMask = CollisionCategories.snake | CollisionCategories.snakeHead view.showsPhysics = true

Теперь создадим кнопки:
let counterClockwiseButton = ControlsFactory.makeButton(at: CGPoint(x: scene.frame.minX + 30, y: scene.frame.minY + 50), name: .counterClockwiseButtonName) addChild(counterClockwiseButton) let clockwiseButton = ControlsFactory.makeButton(at: CGPoint(x: scene.frame.maxX - 90, y: scene.frame.minY + 50), name: .clockwiseButtonName) addChild(clockwiseButton)

Когда вы написали какой-то участок кода, следует подумать о том, можно ли код улучшить или отрефакторить так, чтобы его можно было в дальнейшем переиспользовать. Смотрите, у нас на экране по сути две кнопки, для создания которых используется один и тот же код. А значит, этот код можно вынести в отдельную функцию. Для этого создадим новый класс и, соответственно, файл ControlsFactory.swift со следующим кодом:
import SpriteKit final class ControlsFactory { static func makeButton(at position: CGPoint, name: String) -> SKShapeNode { let button = SKShapeNode() button.path = UIBezierPath(ovalIn: CGRect(x: 0, y: 0, width: 45, height: 45)).cgPath button.position = position button.fillColor = .gray button.strokeColor = UIColor.lightGray.withAlphaComponent(0.7) button.lineWidth = 10 button.name = name return button } }

Чтобы нарисовать рандомное яблоко, которое будет «кушать» наша змейка, создаём класс Apple и файл Apple.swift:
import SpriteKit final class Apple: SKShapeNode { let diameter: CGFloat = 10 convenience init(at point: CGPoint) { self.init() path = UIBezierPath(ovalIn: CGRect(x: -diameter/2, y: -diameter/2, width: diameter, height: diameter)).cgPath fillColor = .red strokeColor = UIColor.red.withAlphaComponent(0.7) lineWidth = 5 position = point physicsBody = SKPhysicsBody(circleOfRadius: diameter / 2, center: .zero) physicsBody?.categoryBitMask = CollisionCategories.apple } }

И описываем наше яблоко функцией createApple() в GameScene.swift:
private func createApple() { let padding: UInt32 = 15 let randX = CGFloat(arc4random_uniform(UInt32(gameFrameRect.maxX) - padding) + padding) let randY = CGFloat(arc4random_uniform(UInt32(gameFrameRect.maxY) - padding) + padding) let apple = Apple(at: CGPoint(x: randX, y: randY).relative(to: gameFrameRect)) gameFrameView.addChild(apple) }

Что же, пришла очередь и для змеи. Она будет состоять из двух частей: тела (SnakeBodyPart.swift) и головы (SnakeHead.swift).

Код SnakeBodyPart.swift:

import SpriteKit class SnakeBodyPart: SKShapeNode { init(at point: CGPoint, diameter: CGFloat = 10.0) { super.init() path = UIBezierPath(ovalIn: CGRect(x: -diameter/2, y: -diameter/2, width: diameter, height: diameter)).cgPath fillColor = .green strokeColor = UIColor.green.withAlphaComponent(0.7) lineWidth = 5 position = point physicsBody = SKPhysicsBody(circleOfRadius: diameter - 4, center: .zero) physicsBody?.isDynamic = true physicsBody?.categoryBitMask = CollisionCategories.snake physicsBody?.contactTestBitMask = CollisionCategories.edgeBody | CollisionCategories.apple } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } }

Код SnakeHead.swift:
import SpriteKit final class SnakeHead: SnakeBodyPart { init(at point: CGPoint) { super.init(at: point, diameter: 20) physicsBody?.categoryBitMask = CollisionCategories.snakeHead physicsBody?.contactTestBitMask = CollisionCategories.edgeBody | CollisionCategories.apple } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } }

Однако не будем вас утомлять описанием каждой строчки, т. к. подробности создания файла GameScene.swift и других классов хорошо отображены в видео. Предлагаем лишь посмотреть итоговый код GameScene.swift:
import SpriteKit import GameplayKit class GameScene: SKScene { var gameFrameRect: CGRect = .zero var gameFrameView: SKShapeNode! var startButton: SKLabelNode! var stopButton: SKLabelNode! var snake: Snake? override func didMove(to view: SKView) { setup(in: view) } override func update(_ currentTime: TimeInterval) { snake?.move() } override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { guard let touchedNode = findTouchedNode(with: touches) else { return } if let shapeNode = touchedNode as? SKShapeNode, touchedNode.name == .counterClockwiseButtonName || touchedNode.name == .clockwiseButtonName { shapeNode.fillColor = .green if touchedNode.name == .counterClockwiseButtonName { snake?.moveCounterClockwise() } else if touchedNode.name == .clockwiseButtonName { snake?.moveClockwise() } } else if touchedNode.name == .startButtonName { start() } else if touchedNode.name == .stopButtonName { stop() } } override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { guard let touchedNode = findTouchedNode(with: touches) else { return } if let shapeNode = touchedNode as? SKShapeNode, touchedNode.name == .counterClockwiseButtonName || touchedNode.name == .clockwiseButtonName { shapeNode.fillColor = .gray } } override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) { guard let touchedNode = findTouchedNode(with: touches) else { return } if let shapeNode = touchedNode as? SKShapeNode, touchedNode.name == .counterClockwiseButtonName || touchedNode.name == .clockwiseButtonName { shapeNode.fillColor = .gray } } // MARK: - private func start() { guard let scene = scene else { return } snake = Snake(at: CGPoint(x: scene.frame.midX, y: scene.frame.midY)) gameFrameView.addChild(snake!) createApple() startButton.isHidden = true stopButton.isHidden = false } private func stop() { snake = nil gameFrameView.removeAllChildren() startButton.isHidden = false stopButton.isHidden = true } private func setup(in view: SKView) { backgroundColor = SKColor.white physicsWorld.gravity = .zero physicsWorld.contactDelegate = self physicsBody = SKPhysicsBody(edgeLoopFrom: frame) physicsBody?.allowsRotation = false physicsBody?.categoryBitMask = CollisionCategories.edgeBody physicsBody?.collisionBitMask = CollisionCategories.snake | CollisionCategories.snakeHead view.showsPhysics = true let margin: CGFloat = 20 let gameFrame = frame.inset(by: view.safeAreaInsets) gameFrameRect = CGRect(x: margin, y: margin + view.safeAreaInsets.top + 55, width: gameFrame.width - margin * 2, height: gameFrame.height - margin * 2 - 55) drawGameFrame() guard let scene = view.scene else { return } let counterClockwiseButton = ControlsFactory.makeButton(at: CGPoint(x: scene.frame.minX + 30, y: scene.frame.minY + 50), name: .counterClockwiseButtonName) addChild(counterClockwiseButton) let clockwiseButton = ControlsFactory.makeButton(at: CGPoint(x: scene.frame.maxX - 90, y: scene.frame.minY + 50), name: .clockwiseButtonName) addChild(clockwiseButton) startButton = SKLabelNode(text: "S T A R T") startButton.position = CGPoint(x: scene.frame.midX, y: 55) startButton.fontSize = 40 startButton.fontColor = .green startButton.name = .startButtonName addChild(startButton) stopButton = SKLabelNode(text: "S T O P") stopButton.position = CGPoint(x: scene.frame.midX, y: 55) stopButton.fontSize = 40 stopButton.fontColor = .red stopButton.name = .stopButtonName stopButton.isHidden = true addChild(stopButton) } final func drawGameFrame() { gameFrameView = SKShapeNode(rect: gameFrameRect) gameFrameView.fillColor = .lightGray gameFrameView.lineWidth = 2 gameFrameView.strokeColor = .green addChild(gameFrameView) } private func findTouchedNode(with touches: Set<UITouch>) -> SKNode? { return touches.map { [unowned self] touch in touch.location(in: self) } .map { atPoint($0) } .first } private func createApple() { let padding: UInt32 = 15 let randX = CGFloat(arc4random_uniform(UInt32(gameFrameRect.maxX) - padding) + padding) let randY = CGFloat(arc4random_uniform(UInt32(gameFrameRect.maxY) - padding) + padding) let apple = Apple(at: CGPoint(x: randX, y: randY).relative(to: gameFrameRect)) gameFrameView.addChild(apple) } } // MARK: - SKPhysicsContactDelegate extension GameScene: SKPhysicsContactDelegate { func didBegin(_ contact: SKPhysicsContact) { var contactMask = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask contactMask ^= CollisionCategories.snakeHead switch contactMask { case CollisionCategories.apple: let apple = contact.bodyA.node is Apple ? contact.bodyA.node : contact.bodyB.node snake?.addBodyPart() apple?.removeFromParent() createApple() case CollisionCategories.edgeBody: stop() break default: break } } } private extension String { static let counterClockwiseButtonName = "counterClockwiseButton" static let clockwiseButtonName = "clockwiseButton" static let startButtonName = "startButton" static let stopButtonName = "stopButton" }

Результатом работы стала простейшая игра Snake:

На написание игры у нас ушло около полутора часов. Если хотите получить навыки программирования на Swift, повторите все этапы самостоятельно. Кстати здесь вы получите полный доступ ко всем файлам кода, которые использовались в данном проекте.

Структуры данных с примерами на языке Swift. Часть первая: связаный список / Хабр

Предисловие

Кто из iOS разработчиков не мечтал о работе в престижном месте вроде Yandex или Avito. К сожалению, про мечты на собеседованиях спрашивает только hr, а вот интервьюеры из числа разработчиков задают вопросы немного другого характера. Чем отличается reference type от value type или bounds от frame? Вопросы, который каждый из нас слышал не раз на собеседованиях. Если ваше интервью начинается с вопроса про отличия значимого и ссылочного типов или в духе “расскажите ка нам про SOLID”, то вы явно на пути трудоустройства в ООО “Так себе перспективы“.

В приличной компании у вас такую ерунду не спросят. Готовьтесь к вопросам про диспетчеризацию, side table и underlying queue. Знания подобных нюансов никоем образом не помогут добиться 60 FPS при скролле, нагруженных элементами ячеек и не сделают вас почетным девелопером России. Они помогут распознать в вас человека, который не просто 4 года менял констрейнты в xib-ах и теперь считает себя Senior iOS Developer, а действительно интересуется платформой. Для меня всегда останется загадкой, в какой момент человек решает, что он достиг уровня Middle или Senior. Наверное участвует в общероссийских соревнованиях, на которых РОС-ГОС-iOS присуждает разряды и звания за выполнение нормативов и призовые места.

Вернемся к собеседованиям. Мало того, что престижный работодатель обязательно задаст заковыристые вопросы по платформе, так еще обязательно спросит про архитектуру. Ждите вопроса: “Почему на прошлом месте вы использовали именно VIPER, а не MVVM?“. Могут поинтересоваться: “Чем плох MVC?“. Ну и последним гвоздем в крышку гроба будут алгоритмы. Даже если вы блестяще разбираетесь в iOS и архитектуре мобильных приложений, но не знаете слабые стороны массивов и не можете оптимизировать поиск элемента, то после собеседования ждите на почту ответ:


На просторах русскоязычного интернета полным-полно статей про алгоритмы и структуры данных. Единственный недостаток, который может омрачить изучение — скудность примеров и реализаций на Swift. Достаточно сложно разбираться в этой теме, когда тебе подсовывают много непонятных слов и еще больше непонятных примеров на C++.

Для всех, кто хочет каждый день пить смузи в шикарных офисах и на встречах выпускников рассказывать как он один тащит на себе всю мобильную разработку Сбера, я подготовил пару статей по структурам данных. Статьи рассчитаны на разработчиков, которые уже знакомы с дженериками, работали с массивами/множествами/словарями, разбираются в отличиях классов от структур и делают вид, что понимают рекурсию. Я не буду расписывать теорию. Это уже сделано до меня и уверен, что достаточно информативно. Сосредоточимся на примерах.

Связаный список

С теорией поможет википедия. Начнем с создания того самого узла.


*обязательно смените свою цветовую схему Xcode на темную иначе не видать вам работы в Mail

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

Каждый уважающий себя эксперт-зануда отметит, что WeakReference какой-то неведомый тип и справедливо потребует реализацию.

Добавим в реализацию методы, отвечающие за наполнение нашего списка:




* Complexity O(1) справедлива только в случае, если нет необходимости копировать структуру. В противном случае у нас будет сложность O(n). Это относится ко всем mutating методам

Добавим методы, отвечающие за удаление из списка:




*@discardableResult избавит нас от необходимости писать "_ = " перед вызовом функции, когда возвращаемое значение нам не интересно

Наша поделка уже выглядит как рабочий связаный список. Попробуем сделать ее максимально Swift-ориентированной. Для этого нам осталось реализовать всего две вещи: BidirectionalCollection протокол и copy-on-write технику. Начнем с протокола. Методов в нем совсем мало и самое сложное это понять и реализовать Index.


Замечательно! Теперь нашему списку доступны все плюшки коллекций. Можем применить к нему map, compactMap, filter, contains и тд. Настала очередь copy-on-write. Реализуем метод copyIfNeeded() из-за отсутствия которого у вас сейчас компилятор намекает на то, что код писал не Д'Артаньян:

Желающих задать умный вопрос или указать на недочеты жду в комментариях.
P.S. Благодарю ivlevAstef за помощь в устранении недочетов. Рабочей реализации без weak обёрток пока никто не предложил.

Код на GitHub

Начало разработки приложений для iOS (Swift): создание базового пользовательского интерфейса

Создание базового пользовательского интерфейса

Этот урок познакомит вас с Xcode, инструментом, который вы используете для написания приложений. Вы познакомитесь со структурой проекта в Xcode и узнаете, как перемещаться между основными компонентами проекта и использовать их. На уроке вы начнете создавать простой пользовательский интерфейс (UI) для приложения FoodTracker и просматривать его в симуляторе. Когда вы закончите, ваше приложение будет иметь метку для названия блюда, текстовое поле для изменения названия блюда и кнопку для сброса названия.

Цели обучения

По окончании урока вы сможете:

  • Создать проект в Xcode

  • Определите назначение ключевых файлов, которые создаются с помощью шаблона проекта Xcode.

  • Открывать и переключаться между файлами в проекте

  • Запустить приложение в iOS Simulator

  • Добавление, перемещение и изменение размеров элементов пользовательского интерфейса в раскадровке

  • Редактируйте атрибуты элементов пользовательского интерфейса в раскадровке с помощью инспектора атрибутов

  • Просмотр и перестановка элементов пользовательского интерфейса с помощью контура

  • Предварительный просмотр пользовательского интерфейса раскадровки в режиме предварительного просмотра редактора Ассистента

  • Используйте Auto Layout для создания пользовательского интерфейса, который автоматически адаптируется к размеру устройства пользователя.

Создать новый проект

Xcode включает несколько встроенных шаблонов приложений для разработки распространенных типов приложений iOS, таких как игры, приложения с навигацией на основе вкладок и приложения на основе таблиц.Большинство этих шаблонов имеют предварительно настроенный интерфейс и файлы исходного кода. В этом уроке вы начнете с самого простого шаблона: приложения для единого просмотра.

Для создания нового проекта

  1. Откройте Xcode из каталога / Applications .

    Если вы запускаете Xcode впервые, он может попросить вас принять пользовательское соглашение и загрузить дополнительные компоненты. Следуйте инструкциям на этих экранах, пока Xcode не будет полностью настроен и готов к запуску.

    Как только Xcode запускается, появляется приветственное окно.

    Если вместо окна приветствия появляется окно проекта, не беспокойтесь - вы, вероятно, уже создали или открыли проект в Xcode. Просто используйте пункт меню на следующем шаге, чтобы создать проект.

  2. В окне приветствия нажмите «Создать новый проект Xcode» (или выберите «Файл»> «Создать»> «Проект»).

    Xcode открывает новое окно и отображает диалоговое окно, в котором вы выбираете шаблон.

  3. Выберите iOS в верхней части диалогового окна.

  4. В разделе «Приложение» выберите «Приложение с одним представлением» и нажмите «Далее».

  5. В появившемся диалоговом окне используйте следующие значения, чтобы назвать свое приложение и выбрать дополнительные параметры для вашего проекта:

    • Название продукта: FoodTracker

      Xcode использует имя продукта, которое вы ввели, чтобы назвать свой проект и приложение.

    • Команда: если это не заполняется автоматически, установите для команды значение Нет.

    • Название организации: название вашей организации или ваше собственное имя. Вы можете оставить это поле пустым.

    • Идентификатор организации: идентификатор вашей организации, если он у вас есть. В противном случае используйте com.example .

    • Идентификатор пакета: это значение создается автоматически на основе названия вашего продукта и идентификатора организации.

    • Язык: Swift

    • Устройства: Универсальные

      Универсальное приложение работает как на iPhone, так и на iPad.

    • Использовать основные данные: не выбрано.

    • Включить модульные тесты: выбрано.

    • Включить тесты пользовательского интерфейса: не выбрано.

  6. Нажмите кнопку "Далее.

  7. В появившемся диалоговом окне выберите место для сохранения проекта и нажмите «Создать».

    Xcode открывает ваш новый проект в окне рабочей области.

В окне рабочей области может отображаться значок ошибки с сообщением «Для подписания на FoodTracker требуется команда разработчиков». Это предупреждение означает, что вы еще не настроили Xcode для разработки под iOS, но не волнуйтесь, вы можете пройти эти уроки и без этого. Для запуска приложения в симуляторе не требуется команда разработчиков.

Исследуй дальше

Прежде чем вы сможете запустить приложение на устройстве iOS, вам необходимо установить допустимую группу, чтобы приложение могло быть подписано.Если вы являетесь частным лицом или частью организации, которая является участником программы Apple Developer Program, вы можете выбрать эту команду здесь. В противном случае ваш Apple ID будет назначен личной команде, которую вы можете использовать для запуска приложений на устройствах. Однако вам нужно будет присоединиться к программе Apple Developer Program, прежде чем вы сможете отправить свое приложение в магазин приложений.

Для получения дополнительных сведений выберите «Справка»> «Справка Xcode» и выполните поиск по запросу «Рабочий процесс подписи».

Ознакомьтесь с Xcode

Xcode включает в себя все, что вам нужно для создания приложения.Он организует все файлы и ресурсы, необходимые для создания приложения. Он предоставляет редакторы как для вашего кода, так и для ваших пользовательских интерфейсов. Кроме того, Xcode позволяет создавать, запускать и отлаживать приложение, предоставляя имитаторы для устройств iOS и мощный интегрированный отладчик.

Уделите несколько минут, чтобы ознакомиться с основными разделами рабочего пространства Xcode:

  • Зона навигатора. Обеспечивает быстрый доступ к различным частям вашего проекта.

  • Область редактора. Позволяет редактировать исходный код, пользовательские интерфейсы и другие ресурсы.

  • Подсобное помещение. Предоставляет информацию о выбранных элементах и ​​доступ к готовым ресурсам. Подсобная часть разделена на две части. Вверху находится панель инспектора, где вы просматриваете и редактируете информацию об элементах, выбранных в навигаторе или областях редактирования. Внизу находится панель библиотеки, где вы получаете доступ к элементам пользовательского интерфейса, фрагментам кода и другим ресурсам.

  • Панель инструментов. Используется для создания и запуска ваших приложений, просмотра хода выполнения задач и настройки вашей рабочей среды.

Не будьте подавлены всеми частями; каждая область описывается более подробно, когда вам нужно ее использовать.

Запуск симулятора iOS

Поскольку вы основали свой проект на шаблоне Xcode, базовая среда приложения автоматически настраивается для вас. Даже если вы не написали никакого кода, вы можете создать и запустить шаблон приложения единого представления без дополнительной настройки.

Чтобы создать и запустить приложение, используйте приложение iOS Simulator, включенное в Xcode. Симулятор дает вам представление о том, как ваше приложение могло бы выглядеть и вести себя, если бы оно работало на устройстве.

Симулятор может моделировать несколько различных типов оборудования - все размеры и разрешения экрана для iPad и iPhone, поэтому вы можете моделировать свое приложение на любом устройстве, для которого вы разрабатываете. В этом уроке используйте вариант iPhone 7.

Для запуска вашего приложения в симуляторе

  1. Во всплывающем меню «Схема» на панели инструментов Xcode выберите iPhone 7.

    Во всплывающем меню «Схема» вы можете выбрать симулятор или устройство, на котором вы хотите запустить приложение. Убедитесь, что вы выбрали симулятор iPhone 7, а не устройство iOS.

  2. Нажмите кнопку «Выполнить», расположенную в верхнем левом углу панели инструментов Xcode.

    Или выберите «Продукт»> «Выполнить» (или нажмите Command-R).

    Если вы запускаете приложение в первый раз, Xcode спрашивает, хотите ли вы включить режим разработчика на вашем Mac.Режим разработчика позволяет Xcode получать доступ к определенным функциям отладки, не требуя каждый раз вводить пароль. Решите, хотите ли вы включить режим разработчика, и следуйте инструкциям.

    Если вы решите не включать режим разработчика, позже вас могут попросить ввести пароль. В этих уроках предполагается, что включен режим разработчика.

  3. Следите за панелью инструментов Xcode по мере завершения процесса сборки.

    Xcode отображает сообщения о процессе сборки в средстве просмотра активности, которое находится в середине панели инструментов.

После того, как Xcode завершит сборку вашего проекта, симулятор запустится автоматически. Первый запуск может занять некоторое время.

Симулятор откроется в указанном вами режиме iPhone, а затем запустит ваше приложение. Сначала симулятор отображает экран запуска вашего приложения, а затем переходит к основному интерфейсу вашего приложения. В немодифицированном шаблоне приложения Single View Application экран запуска и основной интерфейс идентичны.

В настоящий момент шаблон приложения для единого просмотра мало что делает - он просто отображает белый экран.У других шаблонов более сложное поведение. Прежде чем расширять его для создания собственного приложения, важно понимать, как его можно использовать. Запуск вашего приложения в симуляторе без каких-либо модификаций - хороший способ начать развивать это понимание.

Выйдите из симулятора, выбрав Simulator> Quit Simulator (или нажав Command-Q).

Изучите исходный код

Шаблон приложения для единого просмотра поставляется с несколькими файлами исходного кода, которые настраивают среду приложения.Сначала взгляните на файл AppDelegate.swift .

Чтобы посмотреть исходный файл AppDelegate.swift

  1. Убедитесь, что навигатор проекта открыт в области навигатора.

    В навигаторе проекта отображаются все файлы вашего проекта. Если навигатор проекта не открыт, нажмите крайнюю левую кнопку на панели выбора навигатора. (Или выберите «Просмотр»> «Навигаторы»> «Показать навигатор проекта».)

  2. При необходимости откройте папку FoodTracker в навигаторе проекта, щелкнув треугольник раскрытия рядом с ней.

  3. Выберите AppDelegate.swift .

    Xcode открывает исходный файл в области главного редактора окна.

    Также можно дважды щелкнуть файл AppDelegate.swift , чтобы открыть его в отдельном окне.

Исходный файл делегата приложения

Исходный файл AppDelegate.swift выполняет две основные функции:

  • Он определяет ваш класс AppDelegate .Делегат приложения создает окно, в котором отображается контент вашего приложения, и предоставляет место для ответа на переходы между состояниями в приложении.

  • Он создает точку входа в ваше приложение и цикл выполнения, который доставляет события ввода в ваше приложение. Эта работа выполняется с помощью атрибута UIApplicationMain ( @UIApplicationMain ), который отображается в верхней части файла.

    Использование атрибута UIApplicationMain эквивалентно вызову функции UIApplicationMain и передаче имени класса AppDelegate в качестве имени класса делегата.В ответ система создает объект приложения. Объект приложения отвечает за управление жизненным циклом приложения. Система также создает экземпляр вашего класса AppDelegate и назначает его объекту приложения. Наконец, система запустит ваше приложение.

Класс AppDelegate создается автоматически при создании нового проекта. Если вы не делаете что-то очень необычное, вам следует использовать этот класс, предоставляемый Xcode, для инициализации вашего приложения и ответа на события уровня приложения.Класс AppDelegate принимает протокол UIApplicationDelegate . Этот протокол определяет ряд методов, которые вы используете для настройки приложения, реагирования на изменения состояния приложения и обработки других событий на уровне приложения.

Класс AppDelegate содержит единственное свойство: окно , .

Это свойство хранит ссылку на окно приложения. Это окно представляет собой корень иерархии представлений вашего приложения. Здесь отображается весь контент вашего приложения.Обратите внимание, что свойство window не является обязательным, а это означает, что в какой-то момент оно может не иметь значения (быть нулевым).

Класс AppDelegate также содержит реализации-заглушки следующих методов делегата:

  1. func application (_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool
  2. func applicationWillResignActive (_ application: UIApplication)
  3. func applicationDidEnterBackground (_ application: UIApplication)
  4. func applicationWillEnterForeground (_ application: UIApplication)
  5. func applicationDidBecomeActive (_ application: UIApplication)
  6. func applicationWillTerminate (_ application: UIApplication)

Эти методы позволяют объекту приложения взаимодействовать с делегатом приложения.Во время изменения состояния приложения - например, при запуске приложения, переходе в фоновый режим и завершении работы приложения - объект приложения вызывает соответствующий метод делегата, давая вашему приложению возможность ответить. Вам не нужно делать ничего особенного, чтобы эти методы вызывались в нужное время - объект приложения выполняет эту работу за вас.

Каждый из методов делегата имеет поведение по умолчанию. Если вы оставите реализацию шаблона пустой или удалите ее из класса AppDelegate , вы получите поведение по умолчанию при каждом вызове этого метода.В качестве альтернативы вы можете добавить свой собственный код к методам-заглушкам, определяя настраиваемые поведения, которые выполняются при вызове методов.

В шаблоне также есть комментарии для каждого из методов-заглушек. Эти комментарии описывают, как эти методы могут использоваться вашим приложением. Вы можете использовать методы-заглушки и комментарии в качестве схемы для разработки многих общих поведений на уровне приложений.

В этом уроке вы не будете использовать какой-либо пользовательский код делегата приложения, поэтому вам не нужно вносить какие-либо изменения в AppDelegate.swift файл.

Исходный файл контроллера представления

В шаблоне приложения для единого просмотра есть еще один файл исходного кода: ViewController.swift . Выберите ViewController.swift в навигаторе проекта, чтобы просмотреть его.

Этот файл определяет настраиваемый подкласс UIViewController с именем ViewController . Прямо сейчас этот класс просто наследует все поведение, определенное UIViewController . Чтобы переопределить или расширить это поведение, вы переопределяете методы, определенные в UIViewController .

Как видно из файла ViewController.swift , реализация шаблона переопределяет методы viewDidLoad () и didReceiveMemoryWarning () ; однако реализация заглушки шаблона пока ничего не делает, кроме вызова версии UIViewController этих методов. Вы можете добавить свой собственный код, чтобы настроить реакцию контроллера представления на эти события.

Хотя в шаблоне есть метод didReceiveMemoryWarning () , вам не нужно реализовывать его в этих уроках, поэтому удалите его.

На этом этапе ваш код ViewController.swift должен выглядеть примерно так:

  1. импортный УИКит
  2. класс ViewController: UIViewController {
  3. функция переопределения viewDidLoad () {
  4. super.viewDidLoad ()
  5. // Выполните какие-либо дополнительные настройки после загрузки представления, обычно из пера.
  6. }
  7. }

Вы начнете писать код в этом файле исходного кода позже на этом уроке.

Откройте свою раскадровку

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

Чтобы открыть раскадровку

  • В навигаторе проекта выберите Main.storyboard .

    Xcode открывает раскадровку в Interface Builder - его редакторе визуального интерфейса - в области редактора. Фоном раскадровки является холст. Вы используете холст для добавления и упорядочивания пользовательского интерфейса

.

xcode - создание txt файла - swift: IOS

Переполнение стека
  1. Около
  2. Товары
  3. Для команд
  1. Переполнение стека Общественные вопросы и ответы
  2. Переполнение стека для команд Где разработчики и технологи делятся частными знаниями с коллегами
.

Как сделать фреймворк на Swift?

Создание фреймворка Swift не должно быть трудным. Это руководство поможет вам создать универсальный фреймворк для сложных проектов.

Swift

Что такое фреймворк?

Платформа - это иерархический каталог, который инкапсулирует общие ресурсы, такие как динамическая общая библиотека, файлы пера, файлы изображений, локализованные строки, файлы заголовков и справочная документация в одном пакете.

Итак, вкратце, фреймворк - это многократно используемый компонент для ваших приложений.

Как это сделать?

Есть статья о соглашениях Xcode, которая поможет вам организовать ваши проекты, вы должны сначала проверить это, если вы этого не сделали раньше.

Традиционный способ

Существует традиционный способ создания фреймворка в Xcode. Я собираюсь создать общий фреймворк для всех платформ Apple (iOS, macOS, tvOS, watchOS), который будет способен записывать данные в стандартную консоль.

Сделаем проект:

  • Создайте новый проект, используя одну из целей фреймворка
  • Следуйте инструкциям, заполните и назовите все поля
  • Добавить все другие целевые платформы платформы
  • Переименовать все цели в соответствии с названиями платформ

Сейчас в Finder:

  • Создайте папку Sources и переместите туда все файлы Swift и заголовки
  • Создайте папку Assets с подпапками платформ
  • Переместите всю информацию.plist файлы в правильную платформу из подкаталога
  • Создайте папку Tests и переместите туда файлы тестов

Вернуться в Xcode:

  • Удалите все группы и добавьте новые папки из Finder
  • Убедитесь, что у каждой цели есть правильные файлы (фреймворк и тесты)
  • В заголовочном файле замените зависимость UIKit на Foundation

Цель состоит в том, чтобы получить примерно такую ​​структуру:

Настройки проекта:

  • Выберите правильные файлы plist для целей
  • Установите идентификаторы пакета (используйте мои соглашения)
  • Установочные версии платформы (совет: также поддержите 1 старую версию)
  • Настройте файлы plist для тестов из панели настроек сборки
  • Задайте имя продукта (Консоль) в настройках сборки вашего фреймворка
  • Проверьте этапы сборки и добавьте общедоступный файл заголовка.

Настройки схемы:

  • Заходим в настройки схемы и настраиваем общие схемы для фреймворков
  • Соберите данные о покрытии, если они вам нужны
  • Напишите свой фреймворк, вы можете использовать «макросы» Swift для обнаружения платформ.

В Xcode есть флаг, разрешающий только API расширения приложения, если вы встраиваете свою структуру внутри расширения приложения, он должен быть включен!

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


Универсальный кроссплатформенный фреймворк

Можно создать мультиплатформенный проект Xcode с одной схемой с кроссплатформенной поддержкой для каждой платформы, но это не рекомендуется, потому что это взлом. Однако несколько библиотек с открытым исходным кодом делают то же самое, так почему бы и нет.

  • Удалить все цели, схемы, кроме macOS !!!
  • Переименуйте оставшуюся цель, схему (названия платформ нам не нужны)
  • Используйте файл конфигурации проекта, установите xcconfig для проекта
  • Удалить информацию.plist используйте один для фреймворка и один для тестов
  • Переименовать идентификатор пакета (нам там тоже не нужны названия платформ)

Состояния могут быть перепутаны, если вы строите для нескольких платформ, однако это хороший чистый способ поддержки всех платформ без дублирования.


Как использовать Swift framework?

Встраивание вашего фреймворка - самое простое дело. Вы можете просто перетащить проект фреймворка в другой проект Xcode, единственное, что осталось сделать, это встроить фреймворк в приложение.Вы можете перейти в раздел встроенных двоичных файлов на вкладке общей информации о проекте и добавить фреймворк в качестве зависимости.

Менеджер пакетов Swift

При использовании SPM вы должны сначала создать файл Package.swift , затем вы сможете создавать свои цели с помощью команды swift build . Теперь, когда Xcode поддерживает Swift Package Manager, с его помощью действительно легко интегрировать сторонние фреймворки.

Последние примеры фреймворков можно скачать с GitHub.

Убедитесь, что вы не пропустите мой пост, посвященный быстрым фреймворкам.

.

Swift.org - Начало работы

Здесь вы найдете информацию о том, как использовать язык программирования Swift.

Если вы новичок в Swift, ознакомьтесь с A Swift Tour в Язык программирования Swift , для быстрого знакомства с наиболее важные понятия и особенности языка.

Установка Swift

Первым шагом к использованию Swift является загрузка и установка компилятор и другие необходимые компоненты. Перейти на страницу загрузки и следуйте инструкциям для вашей целевой платформы.

Чтобы следовать приведенным ниже примерам, не забудьте добавить Swift в свой $ PATH .

В macOS

Расположение по умолчанию для загружаемой цепочки инструментов в macOS: / Библиотека / Разработчик / Toolchains . Вы можете сделать последнюю установленную цепочку инструментов доступной для использования из терминала с помощью следующей команды:

  $ экспорт TOOLCHAINS = swift  

Чтобы выбрать любой другой установленный набор инструментов, используйте его идентификатор в TOOLCHAINS . переменная.Идентификатор можно найти в файле Info.plist toolchain.

  $ / usr / libexec / PlistBuddy -c "Распечатать CFBundleIdentifier:" /Library/Developer/Toolchains/swift-4.0-RELEASE.xctoolchain/Info.plist org.swift.4020170919 $ export TOOLCHAINS = org.swift.4020170919  

в Linux

  1. Установить необходимые зависимости:
Ubuntu 16.04 Ubuntu 18.04 Ubuntu 20.04 CentOS 7 CentOS 8 Amazon Linux 2
  $ apt-get install \ binutils \ мерзавец \ libc6-dev \ libcurl3 \ libedit2 \ libgcc-5-dev \ libpython2.7 \ libsqlite3-0 \ libstdc ++ - 5-разработчик \ libxml2 \ pkg-config \ tzdata \ zlib1g-dev  
  $ apt-get install \ binutils \ мерзавец \ libc6-dev \ libcurl4 \ libedit2 \ libgcc-5-dev \ libpython2.7 \ libsqlite3-0 \ libstdc ++ - 5-разработчик \ libxml2 \ pkg-config \ tzdata \ zlib1g-dev  
  $ apt-get install \ binutils \ мерзавец \ gnupg2 \ libc6-dev \ libcurl4 \ libedit2 \ libgcc-9-dev \ libpython2.7 \ libsqlite3-0 \ libstdc ++ - 9-разработчик \ libxml2 \ libz3-dev \ pkg-config \ tzdata \ zlib1g-dev  
  $ yum install \ binutils \ gcc \ мерзавец \ glibc-static \ libbsd-devel \ libedit \ libedit-devel \ libicu-devel \ libstdc ++ - статический \ pkg-config \ python2 \ sqlite # __block конфликтует с квалификатором __block clang sed -i -e 's / \ * __ блок / \ * __ libc_block / g' / usr / include / unistd.в  
  $ yum install \ binutils \ gcc \ мерзавец \ glibc-static \ libbsd-devel \ libedit \ libedit-devel \ libicu-devel \ libstdc ++ - статический \ pkg-config \ python2 \ sqlite  
  $ yum install \ binutils \ gcc \ мерзавец \ glibc-static \ gzip \ libbsd \ libcurl \ libedit \ libicu \ libsqlite \ libstdc ++ - статический \ libuuid \ libxml2 \ смола \ tzdata  

Если вы установили набор инструментов Swift в Linux в каталог, отличный от системного корня, вам нужно будет запустить следующую команду, используя фактический путь к вашей установке Swift:

  $ export PATH = / путь / к / Swift / usr / bin: "$ {PATH}"  

в Windows

Visual Studio и Swift

Вам нужно будет установить оба установщика инструментальной цепочки из Страница загрузки и Visual Studio 2019.

Требуются следующие компоненты Visual Studio :

Компонент Visual Studio ID
MSVC v142 - VS 2019 C ++ x64 / x86 инструменты сборки (v14.25) 1 Microsoft.VisualStudio.Component.VC.Tools.x86.x64
Универсальная среда выполнения Windows C Microsoft.VisualStudio.Component.Windows10SDK
Windows 10 SDK (10.0,17763,0) 2 Microsoft.VisualStudio.Component.Windows10SDK.17763

1 Вы можете установить новый набор инструментов сборки.
2 Вместо этого вы можете установить более новый SDK.

Следующие дополнительные компоненты Visual Studio рекомендуются :

Компонент Visual Studio ID
Инструменты C ++ CMake для Windows Microsoft.VisualStudio.Component.VC.CMake.Project
Git для Windows Microsoft.VisualStudio.Component.Git
Python 3 64-разрядная (3.7.8) Component.CPython.x64

Место установки по умолчанию для набора инструментов в Windows: % SystemDrive% \ Library \ Developer \ Toolchains .

Файлы поддержки

Обратите внимание, что для запуска необходимо использовать собственные инструменты x64 для командной строки VS2019 набор инструментов.Собственные инструменты x64 для командной строки VS2019 запускает DevEnv скрипт из Visual Studio, который настраивает необходимую среду переменные, чтобы найти системные заголовки.

Чтобы сделать Windows SDK доступным для Swift, необходимо развернуть несколько файлов в Windows SDK. Следующее изменит вашу Visual Studio Установка, и, как таковая, потребуется запускать из (повышенного) «Администратор» Родные инструменты x86 для командной строки VS2019 .

  копировать% SDKROOT% \ usr \ share \ ucrt.modulemap "% UniversalCRTSdkDir% \ Include \% UCRTVersion% \ ucrt \ module.modulemap" скопируйте% SDKROOT% \ usr \ share \ visualc.modulemap "% VCToolsInstallDir% \ include \ module.modulemap" скопируйте% SDKROOT% \ usr \ share \ visualc.apinotes "% VCToolsInstallDir% \ include \ visualc.apinotes" скопируйте% SDKROOT% \ usr \ share \ winsdk.modulemap "% UniversalCRTSdkDir% \ Include \% UCRTVersion% \ um \ module.modulemap"  

Поскольку файлы устанавливаются в образ Visual Studio, файлы будут необходимо копировать каждый раз при обновлении Visual Studio.


Версия Swift

Вы можете убедиться, что используете ожидаемую версию Swift. введя команду swift и передав флаг --version :

  $ swift --версия Apple Swift версии 2.2-dev (LLVM ..., Clang ..., Swift ...)  

Суффикс -dev в номере версии используется, чтобы указать, что это сборка development , не выпущенная версия.

Использование REPL

Если вы запустите команду swift без других аргументов, вы запустите REPL, интерактивную оболочку который прочитает, оценит и распечатает результаты любого введенного кода Swift.

  $ swift Добро пожаловать в Apple Swift версии 2.2. Тип: help для получения помощи. 1>  

Взаимодействие с REPL - отличный способ поэкспериментировать со Swift. Например, если вы введете выражение 1 + 2 , результат выражения 3 печатается в следующей строке:

Вы можете присваивать значения константам и переменным, и используйте их в последующих строках. Например, String value Hello, world! можно присвоить константе приветствие , а затем передается в качестве аргумента функции print (_ :) :

  2> let welcome = "Привет!" приветствие: String = "Привет!" 3> печать (приветствие) Здравствуйте!  

Если вы введете неверное выражение, REPL выведет сообщение об ошибке, указав, где возникла проблема:

  let answer = "сорок" - "два" ошибка: двоичный оператор '-' нельзя применить к двум операндам типа String let answer = "сорок" - "два" ~~~~~~~ ^ ~~~~~  

Вы можете использовать клавиши со стрелками вверх и вниз ( и ) для циклического просмотра предыдущих строк, введенных в REPL.Это позволяет вам немного изменить предыдущее выражение без повторного набора всей строки, и особенно удобен для исправления ошибок, как в предыдущем примере:

  let answer = "сорок два" ответ: String = "сорок два"  

Еще одна полезная функция REPL в том, что он может автоматически предлагать функции и методы которые можно использовать в конкретном контексте. Например, если вы введете вместо после оператора точки в значении String а затем нажмите клавишу табуляции (), REPL выдаст список доступных доработок например remove (at :) и replaceSubrange (bounds: with :) :

  5> «Привет!».re⇥ Доступные доработки: удалить (в: Индекс) -> Символ removeAll () -> Пустота removeAll (keepCapacity: Bool) -> Пустота removeSubrange (границы: ClosedRange ) -> Пустота removeSubrange (bounds: Range ) -> Пустота replaceSubrange (границы: ClosedRange , с: C) -> Void replaceSubrange (границы: ClosedRange , с: String) -> Void replaceSubrange (bounds: Range , with: C) -> Void replaceSubrange (bounds: Range , with: String) -> Void ReserveCapacity (n: Int) -> Void  

Если вы запускаете блок кода, например, при итерации по массиву с циклом for-in , REPL автоматически сделает отступ для следующей строки, и измените символ приглашения с > на . чтобы указать, что код введен в эту строку будет оцениваться только тогда, когда оценивается весь блок кода.

  6> пусть числа = [1,2,3] числа: [Int] = 3 значения { [0] = 1 [1] = 2 [2] = 3 } 7> для n в числах.reversed () { 8. print (n) 9.} 3 2 1  

Вся функциональность Swift доступна вам из REPL, от написания операторов потока управления для объявления и создания экземпляров структур и классов.

Вы также можете импортировать любые доступные системные модули, например Darwin в macOS и Glibc в Linux:

В macOS

  1> импорт Дарвин 2> arc4random_uniform (10) $ R0: UInt32 = 4  

в Linux

  1> импорт Glibc 2> случайный ()% 10 $ R0: Int32 = 4  

в Windows

REPL зависит от привязок Python.Вы должны убедиться, что Python доступен в пути. Следующая команда добавляет Python в PATH, чтобы его можно было используемый:

  путь% ProgramFiles (x86)% \ Microsoft Visual Studio \ Shared \ Python37_64;% PATH%  

Поскольку установка Windows отделяет SDK от цепочки инструментов, несколько в REPL должны быть переданы дополнительные параметры. Это позволяет использовать несколько разные SDK с одним и тем же набором инструментов.

  установить SWIFTFLAGS = -sdk% SDKROOT% -I% SDKROOT% / usr / lib / swift -L SDKROOT% / usr / lib / swift / windows swift repl -target x86_64-unknown-windows-msvc% SWIFTFLAGS%  

Использование диспетчера пакетов

Менеджер пакетов Swift предоставляет систему на основе соглашений для создание библиотек и исполняемых файлов, а также совместное использование кода в разных пакетах.

В этих примерах предполагается, что вы сделали swift доступным на своем пути; см. Установка для получения дополнительной информации. Когда они станут доступны, вы можете вызвать инструменты диспетчера пакетов: swift package , swift run , swift build и swift test .

  $ быстрый пакет - справка ОБЗОР: выполнение операций с пакетами Swift ...  

Создание пакета

Чтобы создать новый пакет Swift, сначала создайте и войдите в каталог с именем Hello :

Каждый пакет должен иметь файл манифеста с именем Package.swift в корневом каталоге. Вы можете создать минимальный пакет с именем Hello , используя:

По умолчанию команда init создает структуру каталогов пакета библиотеки:

  ├── Package.swift ├── README.md ├── Источники │ └── Привет │ └── Привет. Swift └── Тесты ├── HelloTests │ └── HelloTests.swift └── LinuxMain.swift  

Для сборки пакета можно использовать swift build . Это загрузит, разрешит и скомпилирует упомянутые зависимости. в файле манифеста Package.Сибирский .

  $ быстрая сборка Скомпилируйте модуль Swift 'Hello' (1 источник)  

Чтобы запустить тесты для пакета, используйте: swift test

.

Начать разработку приложений для iOS (Swift): определите свою модель данных

На этом уроке вы определите и протестируете модель данных для приложения FoodTracker. Модель данных представляет структуру информации, хранящейся в приложении.

Цели обучения

По окончании урока вы сможете:

  • Создать модель данных

  • Написание сбойных инициализаторов для настраиваемого класса

  • Продемонстрировать концептуальное понимание разницы между отказоустойчивыми и исправными инициализаторами.

  • Протестируйте модель данных, написав и запустив модульные тесты

Создание модели данных

Теперь вы создадите модель данных для хранения информации, необходимой для отображения сцены приема пищи.Для этого вы определяете простой класс с именем, фотографией и рейтингом.

Чтобы создать новую модель данных класса

  1. Выберите «Файл»> «Создать»> «Файл» (или нажмите Command-N).

  2. В верхней части появившегося диалогового окна выберите iOS.

  3. Выберите Swift File и нажмите Next.

    Вы используете другой процесс для создания этого класса, чем класс RatingControl , который вы создали ранее (iOS> Source> Cocoa Touch Class), потому что вы определяете базовый класс для своей модели данных, что означает, что он не требует наследовать от любых других классов.

  4. В поле «Сохранить как» введите Meal .

  5. По умолчанию в качестве места сохранения используется каталог вашего проекта.

    По умолчанию для параметра «Группа» используется имя вашего приложения - FoodTracker.

    В разделе Targets ваше приложение выбрано, а тесты для вашего приложения не выбраны.

  6. Оставьте эти значения по умолчанию как есть и нажмите «Создать».

    Xcode создает файл с именем Meal.swift .В навигаторе проекта перетащите файл Meal.swift и поместите его под другими файлами Swift, если необходимо.

В Swift вы можете представить имя с помощью String , фото с помощью UIImage и рейтинг с помощью Int . Поскольку у еды всегда есть название и рейтинг, но может не быть фотографии, сделайте UIImage необязательным.

Чтобы определить модель данных для еды

  1. Если помощник редактора открыт, вернитесь в стандартный редактор, нажав кнопку Стандартный.

  2. Откройте Meal.swift .

  3. Измените оператор импорта, чтобы импортировать UIKit вместо Foundation:

    Когда Xcode создает новый файл Swift, он по умолчанию импортирует структуру Foundation, позволяя вам работать со структурами данных Foundation в вашем коде. Вы также будете работать с классом из фреймворка UIKit, поэтому вам нужно импортировать UIKit. Однако импорт UIKit также дает вам доступ к Foundation, поэтому вы можете удалить избыточный импорт в Foundation.

  4. Под оператором импорта добавьте следующий код:

    1. класс Питание {
    2. // МАРК: Свойства
    3. имя переменной: Строка
    4. var фото: UIImage?
    5. оценка var: Int
    6. }

    Этот код определяет основные свойства данных, которые вам нужно хранить.Вы создаете эти переменные ( var ) вместо констант ( пусть ), потому что они должны изменяться на протяжении всего жизненного цикла объекта Meal .

  5. Ниже свойств добавьте этот код для объявления инициализатора:

    1. // МАРК: Инициализация
    2. init (название: String, фото: UIImage?, Рейтинг: Int) {
    3. }

    Напомним, что инициализатор - это метод, который подготавливает экземпляр класса к использованию, что включает в себя установку начального значения для каждого свойства и выполнение любой другой настройки или инициализации.

  6. Заполните базовую реализацию, установив свойства, равные значениям параметров.

    1. // Инициализировать сохраненные свойства.
    2. self.name = name
    3. self.photo = фото
    4. собственный рейтинг = рейтинг

    Но что произойдет, если вы попытаетесь создать Meal с неправильными значениями, такими как пустое имя или отрицательный рейтинг? Вам нужно будет вернуть nil, чтобы указать, что элемент не может быть создан и для него установлены значения по умолчанию.Вам нужно добавить код для проверки этих случаев и вернуть nil , если они не удались.

  7. Добавьте следующий код чуть выше кода, который инициализирует сохраненные свойства.

    1. // Инициализация должна завершиться неудачно, если нет имени или если рейтинг отрицательный.
    2. , если name.isEmpty || рейтинг <0 {
    3. возврат ноль
    4. }

    Этот код проверяет входящие параметры и возвращает ноль , если они содержат недопустимые значения.

    Обратите внимание, что компилятор должен выдать сообщение об ошибке: «Только неудачные инициализаторы могут возвращать« nil »».

  8. Щелкните значок ошибки, чтобы вызвать исправление.

  9. Дважды щелкните исправление, чтобы обновить инициализатор. Подпись инициализатора теперь должна выглядеть так:

    1. init? (Название: String, фото: UIImage?, Рейтинг: Int) {

    Неудачные инициализаторы всегда начинаются с init? или init! .Эти инициализаторы возвращают необязательные значения или неявно развернутые необязательные значения соответственно. Необязательные параметры могут содержать допустимое значение или nil . Вы должны проверить, имеет ли необязательный параметр значение, а затем безопасно развернуть значение, прежде чем его можно будет использовать. Неявно развернутые необязательные параметры являются необязательными, но система неявно развертывает их для вас.

    В этом случае ваш инициализатор возвращает необязательный Meal? объект.

На этом этапе ваш инициализатор ? (Имя: String, фото: UIImage?, Рейтинг: Int) инициализатор должен выглядеть так:

  1. init? (Название: String, фото: UIImage?, Рейтинг: Int) {
  2. // Инициализация должна завершиться неудачно, если нет имени или если рейтинг отрицательный.
  3. , если name.isEmpty || рейтинг <0 {
  4. возврат ноль
  5. }
  6. // Инициализировать сохраненные свойства.
  7. self.name = name
  8. self.photo = фото
  9. самостоятельный рейтинг = рейтинг
  10. }

Исследуй дальше

Как вы увидите в последующих уроках, неудачные инициализаторы труднее использовать, потому что вам нужно развернуть возвращенный необязательный параметр перед его использованием.Некоторые разработчики предпочитают обеспечивать выполнение контракта инициализатора с помощью методов assert (), или precondition () . Эти методы вызывают завершение работы приложения в случае сбоя проверяемого условия. Это означает, что вызывающий код должен проверять входные данные перед вызовом инициализатора.

Для получения дополнительной информации об инициализаторах см. Инициализация. Для получения информации о добавлении встроенных проверок работоспособности и предварительных условий в код см. assert (_: _: file: line :) и precondition (_: _: file: line :) .

Контрольная точка: Создайте проект, выбрав Продукт> Сборка (или нажав Command-B). Вы еще ни для чего не используете свой новый класс, но его создание дает компилятору возможность убедиться, что вы не допустили никаких опечаток. Если да, исправьте их, прочитав предупреждения или ошибки, которые предоставляет компилятор, а затем просмотрите инструкции в этом уроке, чтобы убедиться, что все выглядит так, как описано здесь.

Проверьте свои данные

Несмотря на то, что код вашей модели данных строится, вы еще не полностью включили его в свое приложение.В результате сложно сказать, все ли вы реализовали правильно, и могут ли вы столкнуться с крайними случаями, которые не учли во время выполнения.

Чтобы устранить эту неопределенность, вы можете написать модульные тесты. Модульные тесты используются для тестирования небольших автономных фрагментов кода, чтобы убедиться, что они работают правильно. Meal class - идеальный кандидат для модульного тестирования.

Xcode уже создал файл модульного теста как часть шаблона Single View Application.

Чтобы просмотреть файл модульного теста для FoodTracker

  1. Откройте папку FoodTrackerTests в навигаторе проекта, щелкнув треугольник раскрытия рядом с ней.

  2. Откройте FoodTrackerTests.swift .

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

  1. импорт XCTest
  2. @testable import FoodTracker
  3. class FoodTrackerTests: XCTestCase {
  4. настройка функции отмены () {
  5. супер.setUp ()
  6. // Введите сюда код настройки. Этот метод вызывается перед вызовом каждого тестового метода в классе.
  7. }
  8. Отмена функции отмены () {
  9. // Поместите здесь код разборки. Этот метод вызывается после вызова каждого тестового метода в классе.
  10. супер.tearDown ()
  11. }
  12. func test Пример () {
  13. // Это пример функционального тестового случая.
  14. // Используйте XCTAssert и связанные функции, чтобы убедиться, что ваши тесты дают правильные результаты.
  15. }
  16. func testPerformanceExample () {
  17. // Это пример теста производительности.
  18. Самостоятельное измерение {
  19. // Введите сюда код, который вы хотите измерить.
  20. }
  21. }
  22. }

Код начинается с импорта инфраструктуры XCTest и вашего приложения.

Обратите внимание, что код использует атрибут @testable при импорте вашего приложения.Это дает вашим тестам доступ к внутренним элементам кода вашего приложения. Помните, что по умолчанию Swift использует внутренний контроль доступа для всех типов, переменных, свойств, инициализаторов и функций в вашем коде. Если вы явно не пометили элемент как частный или личный файл, вы можете получить к нему доступ из тестов.

Платформа XCTest - это среда тестирования Xcode. Сами модульные тесты определены в классе FoodTrackerTests , который наследуется от XCTestCase .Комментарии к коду объясняют методы setUp () и tearDown () , а также два примера тестовых случаев: testExample () и testPerformanceExample () .

Основные типы тестов, которые вы можете написать, - это функциональные тесты (чтобы убедиться, что все выдает ожидаемые вами значения) и тесты производительности (чтобы убедиться, что ваш код работает так быстро, как вы ожидаете). Поскольку вы не писали код, требующий высокой производительности, вам пока нужно писать только функциональные тесты.

Тестовые примеры - это просто методы, которые система автоматически запускает как часть ваших модульных тестов. Чтобы создать тестовый пример, создайте метод, имя которого начинается со слова test . Лучше всего давать вашим тестовым примерам описательные имена. Эти названия упрощают идентификацию отдельных тестов в дальнейшем. Например, тест, который проверяет код инициализации класса Meal , может называться testMealInitialization .

Для написания модульного теста для инициализации объекта Meal

  1. В FoodTrackerTests.swift , вам не нужно использовать какие-либо методы-заглушки шаблона для этого урока. Удалите методы шаблона. Ваши тесты на трекере питания должны выглядеть, как показано ниже:

    1. импорт XCTest
    2. @testable import FoodTracker
    3. class FoodTrackerTests: XCTestCase {
    4. }
  2. Перед последней фигурной скобкой (} ) добавьте следующее:

    Это комментарий, который поможет вам (и всем, кто читает ваш код) ориентироваться в ваших тестах и ​​определять, чему они соответствуют.

  3. Под комментарием добавьте новый тестовый пример:

    1. // Подтвердите, что инициализатор Meal возвращает объект Meal при передаче допустимых параметров.
    2. func testMealInitializationSucceeds () {
    3. }

    Система автоматически запускает этот тестовый пример при запуске модульных тестов.

  4. Добавьте в тестовый пример тесты, которые не используют рейтинг и используют самый высокий положительный рейтинг.

    1. // Нулевой рейтинг
    2. let zeroRatingMeal = Meal.init (имя: "Zero", фото: nil, рейтинг: 0)
    3. XCTAssertNotNil (zeroRatingMeal)
    4. // Наивысший положительный рейтинг
    5. let positiveRatingMeal = Meal.init (name: "Positive", фото: nil, рейтинг: 5)
    6. XCTAssertNotNil (positiveRatingMeal)

    Если инициализатор работает должным образом, эти вызовы init (name :, photo :, rating :) должны завершиться успешно. XCTAssertNotNil проверяет это, проверяя, что возвращенный объект Meal не равен nil .

  5. Теперь добавьте тестовый пример, когда инициализация класса Meal должна завершиться ошибкой. Добавьте следующий метод в метод testMealInitializationSucceeds () .

    1. // Подтвердите, что инициатор Meal возвращает ноль, когда передается отрицательный рейтинг или пустое имя.
    2. func testMealInitializationFails () {
    3. }

    Опять же, система автоматически запускает этот тестовый пример при запуске модульных тестов.

  6. Теперь добавьте тесты в тестовый пример, который вызывает инициализатор с недопустимыми параметрами.

    1. // Отрицательный рейтинг
    2. let negativeRatingMeal = Meal.init (name: "Negative", фото: nil, рейтинг: -1)
    3. XCTAssertNil (negativeRatingMeal)
    4. // Пустая строка
    5. пусть emptyStringMeal = Еда.init (name: "", фото: nil, рейтинг: 0)
.

Swift.org - Документация

Вы можете использовать ресурсы на этой странице в качестве документации по языку Swift. Apple размещает дополнительные ресурсы для изучения Swift, такие как видео, примеры кода и игровые площадки, а также дополнительную документацию, включая Справочник по стандартной библиотеке Swift.

Язык быстрого программирования

Язык программирования Swift является авторитетным справочником по Swift, предлагает экскурсию, исчерпывающий гид и официальную справку по языку.Вы можете прочитать книгу здесь:

Вы также можете загрузить последнюю версию в формате ePub по лицензии Creative Commons Attribution 4.0 International (CC BY 4.0).

Переводы

Мы призываем вас принять участие в переводе The Swift Programming Language на другие языки. Примите участие в существующем переводческом проекте или начните новый, если в этом возникнет необходимость. Отличный пример - язык программирования Swift (перевод на китайский язык, проект GitHub).

Если вы знаете о проекте качественного перевода, сообщите нам об этом на форумах по разработке компиляторов, и мы сделаем все возможное, чтобы на этой странице была ссылка на этот проект.

Менеджер пакетов Swift

Swift Package Manager - это инструмент для управления распространением кода Swift. Он интегрирован с системой сборки Swift для автоматизации процесса загрузка, компиляция и связывание зависимостей. Манифест диспетчера пакетов Документация по API доступна здесь.

Руководство по проектированию API

Цель Swift состоит в том, чтобы код разделял единый стандарт для программистов. пользовательский опыт, большая часть которого определяется именами и идиомами, которые появляются в API. Эти рекомендации по дизайну объясняют, как убедитесь, что ваш код ощущается как часть более крупной экосистемы Swift.

Руководства по миграции

Xcode включает инструмент Swift Migrator, который поможет вам перенести ваш проект на последнюю версию Swift, или обновите его для работы с последними SDK.

.

Смотрите также