@IBOutlet и @IBAction в Swift
Очень хотел бы понять что происходит под капотом, когда мы создаем для, например, UITableView @IBOutlet (и заодно @IBAction ) в нашем классе, по умолчанию, в single view app , это ViewController . Использую XCode 9, Swift 4.
Отслеживать
15.8k 1 1 золотой знак 18 18 серебряных знаков 35 35 бронзовых знаков
задан 16 июл 2018 в 13:35
123 3 3 серебряных знака 14 14 бронзовых знаков
1 ответ 1
Сортировка: Сброс на вариант по умолчанию
Пример для объяснения аналогичный Вашему, но вместо UITableView разместил UIButton и UILabel . Создал для них IBOutlet и для кнопки IBAction :
class ViewController: UIViewController < @IBOutlet weak var someLabel: UILabel! @IBOutlet weak var someButton: UIButton! @IBAction func someButtonAction(_ sender: UIButton) < print(#function) >>
Чтобы посмотреть содержимое Storyboard , необходимо в меню выбрать Open As -> Source Code :

Это обычный xml . Далее содержимое с пояснениями:
По сути, storyboard является эдаким DI контейнером.
Начало разработки iOS: использование Interface Builder
Добро пожаловать в третий выпуск видео-серии «Начало разработки iOS». В этом уроке мы рассмотрим Интерфейсный Разработчик и как мы можем использовать его в проектах iOS.
Примечания ниже дополняют видео. Если у вас есть какие-либо вопросы относительно чего-либо, упомянутого в видео, пожалуйста, не стесняйтесь спрашивать в разделе комментариев.
Начиная
Сначала рассмотрим интерфейс Interface Builder. После открытия XIB вы увидите 4 разных окна. Окно «Библиотека», «Вид / Окно», «Окно документа» и окно «Атрибуты», «Размер», «Соединения и личность». Если вы не видите ни одного, ни одного из этих окон, убедитесь, что Интерфейсный Разработчик работает, заново открыв окна из меню Инструменты.
Библиотека
В этой библиотеке все объекты UIKit доступны для использования в вашем проекте. Простое перетаскивание объекта в окно добавит его в представление. Библиотека разделена на 3 раздела.
- Контроллеры. Это объекты, которые управляют набором связанных представлений в определенном контексте контента. Примером может служить Контроллер сообщений, показывающий сообщения, доступные пользователю.
- Представления данных: когда данные должны отображаться пользователю, эти представления будут соответствовать большинству типов мультимедиа. Таблицы, изображения, веб-страницы, карты и прокрутка содержимого обрабатываются объектами в этой категории.
- Входные данные и значения: когда пользователю требуется ввести информацию или предоставить выбор, эти объекты предоставляют множество различных опций.
Использование контроллеров, а не объектов пользовательского интерфейса
Если вы хотите использовать UITabBar в своем приложении, вы не перетаскиваете UITabBar в представление. Как вы используете UITabBar, UINavigationBar и панель поиска, с помощью контроллера. Контроллер выходит из этих объектов и автоматически обрабатывает основные функциональные возможности этих объектов. Использование контроллера UITabBar будет автоматически обрабатывать переход и управление различными UIViewControllers.
Расширения UIView
Все основные объекты UIKit происходят от класса UIView. В Какао все развивается в наследственной древовидной форме. Никакая функциональность не дублируется, если она может быть унаследована. Под этим я подразумеваю, что объект UIButton, например, является потомком класса UIView. Из-за этого UIButton наследует альфа-канал, режим содержимого, размер и другие характеристики, которые имеет класс UIView, но также распространяется на функции с дополнительной функциональностью, например, в качестве кнопки.

На приведенном выше снимке экрана Interface Builder показано, что класс UIButton наследуется от класса UIControl, который, в свою очередь, наследуется от класса UIView и так далее. Все это основано на классе NSObject, который вы найдете в качестве основы любого класса Какао. Каждый из этих классов, унаследованных друг от друга, приносит функциональность друг другу, а затем расширяется.
Атрибуты, связи, размер и идентичность
Это окно позволяет изменить свойства и настройки для выбранного объекта UIView. В зависимости от объекта пользовательского интерфейса вы можете изменить настройки шрифта, стиль объекта, цвета фона или прозрачность.
В разделе соединений будут показаны все доступные действия, на которые может реагировать объект, а также любые связанные розетки или действия.
Размер раздела делает, как вы ожидаете. Вы можете изменить координаты X & Y объекта, а также его физические размеры. Сюда также входят параметры автоматического изменения размера, которые управляют изменением размера элемента в случае поворота экрана или изменения размера.
Раздел идентичности обычно не используется, но в нем есть несколько интересных полей. Если вы расширили объект UIKit и хотите использовать собственный класс вместо стандартного, то здесь вы можете переназначить базовый класс объектов. Есть несколько опций, связанных с доступностью и внутренними полями Interface Builder, такими как заметки и разрешение именования объектов.
Autosizing
Когда экран поворачивается на устройстве iOS, вы можете управлять тем, как объекты пользовательского интерфейса будут изменять свое положение или растягиваться, чтобы заполнить новое окно. Всем этим можно управлять с помощью этого простого небольшого инструмента в Интерфейсном Разработчике.

Поле слева – это место, где вы решаете, как будет масштабироваться объект, а поле справа – это анимированная визуализация того, как будет работать объект при изменении фрейма макета.
Внешний блок слева – это то место, где вы устанавливаете «якоря» или то, с каких сторон объект будет блокироваться. Любая выбранная сторона заставит объект придерживаться этой стороны при изменении размеров экрана. Внутренний квадрат имеет элементы управления для растяжения. Когда объект заблокирован с двух сторон и экран меняет свою ширину, объект может быть растянут вместе с экраном. Стоит поиграть с этими настройками и посмотреть результаты разных конфигураций.
IBActions и IBOutlets
Когда вам нужно соединить ваш код с объектом в Интерфейсном Разработчике, вы используете IBAction и IBOutlet. Эти ключевые слова являются флагом для Интерфейсного Разработчика, чтобы знать, что есть свойство, доступное для соединения с контроллером. Затем вы соединяете соответствующий объект с действием или розеткой. IBAction – это то, как объект может связаться с вашим кодом, когда происходит событие. Когда нажата кнопка, вы используете IBAction для вызова метода обратно в вашем контроллере. IBOutlet – это обратный способ взаимодействия вашего контроллера с объектом в Интерфейсном Разработчике и вашим представлением в любое время.
Создать IBOutlet так же просто, как добавить флаг, когда вы определяете свойство объекта в вашем контроллере.
@interface HelloInterfaceBuilderViewController: UIViewController IBOutlet UILabel * myText; > @property (nonatomic, retain) IBOutlet UILabel * myText;
IBAction похож. При определении метода в заголовочном файле вы добавляете флаг IBAction в качестве возвращаемого типа.
@interface HelloInterfaceBuilderViewController: UIViewController // . IBOutlets и свойства . > - (IBAction) кнопкаPressed: (id) отправитель;
Соединить их – простая задача в Интерфейсном Разработчике.
При создании IBAction: нажмите на объект в окне, удерживайте элемент управления, перетащите к «Владельцу файлов» в окне документа, отпустите кнопку мыши и затем управляйте. Выберите действие для ссылки в раскрывающемся списке.
При создании IBOutlet: щелкните «Владелец файлов» в окне документа, удерживайте элемент управления, перетащите элемент «Владелец файлов» к объекту в окне, отпустите кнопку мыши, а затем элемент управления. Выберите розетку из раскрывающегося списка.
Плюсы и минусы Interface Builder и XIB
В этом вопросе нет сплошных уй или нет. По общему мнению, использование Interface Builder и XIB не более интенсивно, чем создание объектов в вашем контроллере. Есть некоторые побочные эффекты от того или иного пути.
При использовании XIB легко баловать представления объектами и не учитывать последствия для памяти. В большинстве случаев беспокоиться не о чем, но в чувствительных частях приложения UITableView является одной из этих чувствительных областей, перегрузка интерфейса может вызвать замедление работы приложения. Помните, что каждый объект в представлении имеет свое собственное распределение памяти и создается, когда представление загружается в приложение, является ключевым.
Программирование без XIB позволяет размещать объекты в тот самый момент, когда объект требуется, и освобождать, как только он не нужен. Это сохраняет приложение легким и отзывчивым, пока ничего не просачивается (забудьте освободить объект). Но поскольку все это делается в коде, визуальное представление того, что было создано, отсутствует, пока приложение не находится в симуляторе. Интерфейсный Разработчик позволяет интерактивно создавать представление, редактор WYSIWYG. Таким образом, в результате некоторые представления без XIB могут выглядеть как роботизированные или мягкие, потому что разработчик не украсил дизайн.
Нет определенного решения. Если какой-то способ чувствует себя лучше, тогда это совершенно нормально. В большинстве случаев между ними нет заметных различий в производительности.
Пояснение: в скринкасте упоминается, что XIB преобразуются из XML в интерфейс на устройстве во время выполнения. Это не вариант. XIB компилируются в NIB при создании приложения и используются в приложении в качестве NIB. Тип файла XIB был создан, чтобы позволить службам управления исходным кодом, таким как SVN и Git, работать лучше с файлом на основе XML (чтобы можно было выполнять diff), а не скомпилированным двоичным файлом.
А в ваших iOS приложениях IBOutlet уже private?

Вы наверняка использовали Storyboard или XIB для верстки интерфейсов? Верстать из кода это прекрасно, но иногда намного проще понять как устроен какой-то из компонентов интерфейса, увидев его, а не прочитав. В этой записи я хочу обсудить необходимость использования для IBOutlet модификатора private.
Разработчиков, для которых инкапсуляция IBOutlet является очевидной, тут вряд ли что-то удивит, зато может быть интересен опрос в конце статьи.
Представим, что вы собираетесь создать IBOutlet (ссылку на View с Storyboard) для какого-нибудь из ваших UILabel. При перетаскивании мышкой Xcode заботливо создаст нам что-то вроде
@IBOutlet weak var myLabel: UILabel!
Я долгое время считал эту конструкцию оптимальной, до того момента как мой коллега не спросил — а почему твои IBOutlet не private?
В самом деле, зачем мне оставлять все IBOutlet-ы доступными извне?
Представим себе классическую задачу — у нас есть ячейка, в которой отображается, к примеру, чей-то контакт
import UIKit class ContactCell: UITableViewCell < @IBOutlet private weak var nameLabel: UILabel! @IBOutlet private weak var positionLabel: UILabel! override func awakeFromNib() < super.awakeFromNib() >func setupCell(withContact contact: Contact) < nameLabel.text = contact.name positionLabel.text = contact.position >>
С помощью добавления private к привычным нам IBOutlet можно гарантировать, что указанные поля ячейки не будет заданы из другого класса. Особенно это может быть полезно при командной работе, когда кто-то по неосторожности / нехватке времени / глупости (нужное подчеркнуть) попробует задать цвета, текст или какие-то другие свойства у Label-ов ячейки прямо в методе tableView(_:cellForRowAt:).
А представьте, что ячейка или целый ViewController содержит множество IBOutlet-ов, что настроек отображения масса. Не проще ли обезопасить себя добавлением private, чем потом искать почему внешний вид элемента вдруг изменился или откуда-то появился Gesture Recognizer, который задает неожиданное поведение?
P.S.: Если после прочтения вам захочется использовать private для IBOutlet-ов, то для простоты можно завести для этого снипет в Xcode.
Ниже приведен опрос, если вы захотите прокомментировать свой вариант ответа, welcome в комментарии.
Использование блоков в iOS. Часть 1
В процессе изучения Objective-C и iOS-разработки не могла понять принципы работы блоков. С толку сбивало, что их можно передавать как параметры в методы. Наткнулась на статью, которая показалась мне крайне интересной, так как рассматривались не только блоки, но и процесс разработки приложения. Пост адаптирован под xCode 7.3.1.
Предисловие
Блоки — невероятно мощное добавление к C/Objective-C, позволяющее «обернуть» куски кода в отдельные единицы и оперировать ими в качестве объектов. Все больше и больше API требуют использование блоков в iOS, поэтому очень важно их понимать. Однако, их синтаксис и некоторые тонкие аспекты зачастую сбивают с толку начинающих. Но бояться не стоит — этот урок будет весьма полезным.
В двух частях этого урока мы создадим небольшой iOS проект «iOS Diner». Приложение само по себе простое: пользователь выбирает блюдо из меню для создания заказа, как будто бы собираясь пообедать. Осторожно: в процессе создания обостряется чувство голода!
В первой части разработаем UI нашего приложения, заодно рассмотрев Storyboard (дословно — раскадровка — Прим. пер.), включая небольшую памятку по созданию и использованию веб-сервисов для загрузки меню в формате JSON.
Примечание. Если вы уже довольно хорошо разбираетесь со Storyboard и Interface Builder, можете пропустить первую часть и сразу перейти ко второй части, где мы начнем использовать блоки. Эта часть фокусируется только на Storyboard и Interface Builder.
Во второй части будет показано всестороннее использование блоков для программирования логики приложения, асинхронной обработки данных, фоновых задач, использования в качестве альтернативы многим стандартным API, и многое другое.
Начинаем
Открываем Xcode и создаем новый проект.

В названии проекта укажите «iOSDiner».

Запустите проект. Конечно, он еще пустой, и на симуляторе будет пустой белый экран.

В настройках проекта в Deployment Info убираем галочку Portrait.

Первое, что мы сделаем, — настроим представление. Для этого понадобится немного графики. Скачать можно отсюда. Это нужно будет добавить в ресурсы проекта.
Если честно, мне никогда не нравилось, как xCode обрабатывает совпадение файлов в проекте и файловой системе, поэтому обычно я добавляю ресурсы вручную в файловой системе. В Finder откройте папку проекта и в ней создайте папку «Resources». В ней создайте папку «Images».

Скопируйте графику из загруженного ZIP-файла в папку Images, затем перетащите папку Resources в папку IOSDiner в Xcode, как показано на скриншоте ниже.

Теперь можно увидеть папку Resources в Xcode, в которой есть подпапка Images с загруженными изображениями, — как и в файловой системе.
Добавление изображений
Откройте Main.storyboard.

Если вы не видите вторую колонку с названием «View Controller Scene», внизу кликните на кнопку Expand.
Итак, мы собираемся добавить изображения в Storyboard в виде UIImageViews и UIButtons. Чтобы было проще, откройте боковую панель Utilities и выберите Media Library.

Здесь мы видим все раннее добавленные в проект изображения. Наверняка вы заметили, что у каждой картинки есть своя копия с «@2x» в конце названия. Она используется для retina-версии.
Мы заинтересованы только в обычной картинке. Вы можете проверить, какая это версия картинки, кликнув и нажав клавишу пробел. Перетащите “bg_wall.png” на root-view, как показано ниже. Если вы не уверены, что изображение поставлено корректно, можете переключиться в Size Inspector для изменения его X и Y координат.


Теперь проделайте то же самое со следующими изображениями:
- person.png
- sign_theiOSdiner.png
- chalkboard.png
- bg_counter.png
- total_field.png
- food_box.png

Вау! Почти похоже на приложение! Далее, добавим части пользовательского интерфейса. На панели Utilities переключитесь на Object Library.
Перетащите Button в центр нашего представления, над монитором. Дважды кликните на только что добавленную кнопку и напишите «-1».

Round Rect Button
В оригинале использовались Round Rect Button, которые отсутствуют в xCode 7.3.1. На Stack Overflow есть решение, как их использовать.
Убедитесь, что кнопка выделена. В Attributes Inspector установите атрибут Background «button_silver.png».Нажмите и удерживайте клавишу Alt и перетащите кнопку -1 вправо. Так создастся копия объекта. Измените ее текст на «+1».


Перетащите еще одну кнопку на левый край монитора. Установите Button Type в Custom, удалите заголовок кнопки и из Media Library перетащите на кнопку «button_arrow_left.png»

Скопируйте эту кнопку и поменяйте фоновое изображение на «button_arrow.png»

И осталась последняя кнопка. Разместите ее под доской и установите фоновое изображение «total_field.png». Запустите проект.

Выглядит вполне симпатично. Следующее, что мы добавим, — лейблы и окошко предварительного просмотра.
Снова идем в Object Library. Перетаскиваем UILabel на доску и растягиваем его по размеру доски.

В Atrributes Inspector установите Lines в 0 (это сделает лейбл многострочным), поменяйте Text Color на белый, и Font — на Marker Felt 17.0. Обычно использование Marker Felt я считаю преступлением, но в нашем случае он вполне подходит.

Перетащите UIImageView на монитор и растяните по его размеру.

В Attributes Inspector поменяйте Mode на Aspect Fit.

Перетащите еще один UILabel на табличку в правом нижнем углу. Сделайте его по размеру серой зоны таблички и установите Alignment в Center.

Устанавливаем IBOutlets и IBActions
Далее необходимо установить связи между пользовательским интерфейсом, который мы только что создали, и кодом. Для этого и нужны IBOutlets и IBActions. IB означает Interface Builder, который используется для создания UI в xCode.
- IBOutlet, в основном, — это связь элемента UI (кнопки или лейбла) с его ссылкой в коде.
- IBAction — это действие (или метод, как удобнее) в коде, которое можно подключить к некоторому событию (нажатие кнопки, например) в разработанном интерфейсе.
Закройте вкладку Utilities и откройте Assistant editor. В зависимости от того, как он настроен, экран может выглядеть не так, как на скриншоте. Если вы хотите изменить отображение Assistant editor, загляните в его меню.

Начнем с кнопок. Выберите кнопку «-1», удерживайте клавишу Ctrl и перетащите ее в код. Это автоматизирует создание IBOutlet для кнопки.
Для этого объекта все, что нужно, — назвать его. Мне нравятся префиксы «ib», так как в xCode становится легко найти все элементы по автозаполнению. Назовите этот объект «ibRemoveItemButton» и кликните Connect.

Аналогично делаем с остальными кнопками.




Точно так же устанавливаем лейблы.



Теперь ViewController.m должен выглядеть так:
#import "ViewController.h" @interface ViewController () @property (weak, nonatomic) IBOutlet UIButton *ibRemoveItemButton; @property (weak, nonatomic) IBOutlet UIButton *ibAddItemButton; @property (weak, nonatomic) IBOutlet UIButton *ibPreviousItemButton; @property (weak, nonatomic) IBOutlet UIButton *ibNextItemButton; @property (weak, nonatomic) IBOutlet UIButton *ibTotalOrderButton; @property (weak, nonatomic) IBOutlet UILabel *ibChalkboardLabel; @property (weak, nonatomic) IBOutlet UIImageView *ibCurrentItemImageView; @property (weak, nonatomic) IBOutlet UILabel *ibCurrentItemLabel; @end @implementation ViewController - (void)viewDidLoad < [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. >- (void)didReceiveMemoryWarning < [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. >@end
Теперь мы должны добавить IBActions для UIButtons. Это методы, которые вызываются в ответ на определенные события (Touch Up Inside, Touch Up Outside, Touch Cancel, и т.д.). Для кнопок чаще всего используется Touch Up Inside.
Выберем кнопку «-1». Снова с помощью клавиши Ctrl перетаскиваем ее в ViewController.m. Так как это IBAction, используем префикс «iba». Повторяем для всех кнопок.





Устанавливаем веб-сервис
Прежде чем приступить к коду, настроим веб-сервис. Я не собираюсь объяснять все в мельчайших подробностях, так как для этого уже существует несколько уроков (How To Write A Simple PHP/MySQL Web Service for an iOS App и How to Write an iOS App That Uses a Web Service).
Код ниже показывает, как будет выглядеть PHP код для веб-сервиса.
'Continue', 101 => 'Switching Protocols', 200 => 'OK', 201 => 'Created', 202 => 'Accepted', 203 => 'Non-Authoritative Information', 204 => 'No Content', 205 => 'Reset Content', 206 => 'Partial Content', 300 => 'Multiple Choices', 301 => 'Moved Permanently', 302 => 'Found', 303 => 'See Other', 304 => 'Not Modified', 305 => 'Use Proxy', 306 => '(Unused)', 307 => 'Temporary Redirect', 400 => 'Bad Request', 401 => 'Unauthorized', 402 => 'Payment Required', 403 => 'Forbidden', 404 => 'Not Found', 405 => 'Method Not Allowed', 406 => 'Not Acceptable', 407 => 'Proxy Authentication Required', 408 => 'Request Timeout', 409 => 'Conflict', 410 => 'Gone', 411 => 'Length Required', 412 => 'Precondition Failed', 413 => 'Request Entity Too Large', 414 => 'Request-URI Too Long', 415 => 'Unsupported Media Type', 416 => 'Requested Range Not Satisfiable', 417 => 'Expectation Failed', 500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Timeout', 505 => 'HTTP Version Not Supported' ); return (isset($codes[$status])) ? $codes[$status] : ''; > // Helper method to send a HTTP response code/message function sendResponse($status = 200, $body = '', $content_type = 'text/html') < $status_header = 'HTTP/1.1 ' . $status . ' ' . getStatusCodeMessage($status); header($status_header); header('Content-type: ' . $content_type); echo $body; >class InventoryAPI < function getInventory() < $inventory = array( array("Name"=>"Hamburger","Price"=>0.99,"Image"=>"food_hamburger.png"), array("Name"=>"Cheeseburger","Price"=>1.20,"Image"=>"food_cheeseburger.png"), array("Name"=>"Fries","Price"=>0.69,"Image"=>"food_fries.png"), array("Name"=>"Onion Rings","Price"=>0.69,"Image"=>"food_onion-rings.png"), array("Name"=>"Soda","Price"=>0.75,"Image"=>"food_soda.png"), array("Name"=>"Shake","Price"=>1.20,"Image"=>"food_milkshake.png") ); sendResponse(200, json_encode($inventory)); > > sleep(5); $api = new InventoryAPI; $api->getInventory(); ?>
Этот веб-сервис представляет собой вполне простой PHP-скрипт, который возвращает JSON-массив. В массиве находится так называемый ассоциативный массив (PHP), или словарь(Objective-C), в котором содержится название, цена и имя изображения для предмета. Единственное, что следует отметить в вышеуказанном коде, — это строчка sleep(5); .
Я использую ее для симуляции медленного веб-сервиса, чтобы лучше показать, как блоки могут помочь с асинхронными операциями.
Вы можете скопировать этот код в файл с расширением .php и разместить его на хостинге, или просто используйте мой.
Что делать дальше
Проект этой части урока можно скачать здесь. Что ж, здесь было много всяких вещей, никак не связанных с блоками. Но сейчас, установив view и веб-сервис, мы можем перейти к кодингу, где и будем использовать блоки, чтобы сделать наше приложение полностью функционирующим.
- ios development
- objective-c
- перевод