Инстанциирование классов и экземпляры — Python: Введение в ООП
Экземпляры
Класс, как мы уже увидели, может хранить данные. Но типичный класс присутствует в программе в единственном экземпляре. Поэтому сам по себе класс не очень полезен, ведь хранить определения можно и в модулях. Весь смысл использования классов заключается в их инстанциировании.
Инстанциированием (instantiation) называют процесс (акт) создания на основе класса экземпляра (instance) — такого объекта, который получает доступ ко всему содержимому класса, но при этом обладает и способностью хранить собственные данные. При этом, имея объект, всегда можно узнать, экземпляром какого класса он является.
Давайте объявим класс и создадим пару экземпляров, а заодно и познакомимся с синтаксисом инстанциирования классов:
При выводе объекта класса в REPL можно увидеть строку, похожую на вывод информации о классе, только вместо «class» в строчке упоминается «object».
Атрибуты класса и экземпляры
В предыдущем примере класс был пустой. Теперь воспроизведём его, но добавим на этот раз атрибут:
Давайте же переименуем Боба:
Вот вы и увидели то самое «собственное состояние объекта»! Person продолжает давать имя всем экземплярам, пока те не изменят значение своего атрибута. В момент присваивания нового значения атрибуту экземпляра, экземпляр получает свой собственный атрибут!
Стоит прямо сейчас заглянуть «под капот» объектной системы Python, чтобы вы в дальнейшем могли исследовать объекты самостоятельно. Это и интересно, и полезно — как при обучении, так и при отладке объектного кода.
Итак, внутри каждого объекта Python хранит… словарь! Имена атрибутов в пространствах имён выступают ключами этого словаря, а значения являются ссылками на другие объекты. Словарь этот всегда называется __dict__ и тоже является атрибутом. Обращаясь к этому словарю, вы можете получить доступ к значениям атрибутов:
Надо сказать, что это очень разумный подход! Да, Python мог бы копировать словарь класса при инстанциировании. Но это привело бы к излишнему потреблению памяти. А вот «коллективное использование», напротив, позволяет память экономить!
И, конечно же, словарь __dict__ объекта может быть изменён. Когда мы давали Бобу имя, мы на самом деле сделали что-то такое:
Мы даже можем добавить Бобу фамилию и сделать это через модификацию __dict__ :
Проверка принадлежности экземпляра к классу
Как вы уже могли заметить, в Python многие «внутренние штуки» имеют имена, заключённые в двойные символы подчёркивания. В разговоре питонисты обычно проговаривают подобные имена примерно так: «дАндер-класс», что является калькой с «dunder class», где «dunder», в свою очередь, это сокращение от «double underscore», то есть «двойной символ подчеркивания». Полезно запомнить этот стиль именования!
А ещё стоит запомнить, что практически всегда, когда вы хотите использовать что-то, названное в dunder-стиле, «есть способ лучше»! Так с __dict__ напрямую работать не приходится, потому что есть возможность обращаться к атрибутам «через точку». Вот и __class__ в коде встречается редко. А рекомендуемый способ проверки принадлежности к классу выглядит так:
Открыть доступ
Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно.
Понятие класса, экземпляра класса и объекта в ООП.
Независимо от того, какой язык программирования вы собираетесь изучать: PHP, Javascript или др. языки программирования, при изучении объектно-ориентированного подхода к программированию, обязательно нужно разобраться с понятиями класса и объекта.
Из предыдущего видео мы знаем, что самым главным действующим лицом в объектно-ориентированном подходе программирования является объект, у которого есть какие-то свойства (т.е. характеристики этого объекта), значения этих свойств и методы, те действия, которые этот объект может совершать.
Но, для того, чтобы в нашей программе появился объект, нужно совершить два действия:
1) Его нужно описать. Какие свойства и методы есть у этого объекта.
2) Его нужно создать
Что значит описать объект? Описание объекта – это определение его свойств и методов, которые этот объект может принимать. Т.е. мы начинаем создавать программу и пишем, что у нас будет некий объект (например, Employee или Работник).
У этого объекта будет свойства first_name (имя), last_name (фамилия), age (возраст).
Этот объект при запросе к нему может выдавать его имя (getFirstName()), фамилию getLastName()), возраст (getAge()).
Обратите внимание, что в конце метода ставятся круглые скобки (). Они обозначают то, что это является методом. Остальное является свойствами, характеристиками объекта.
Что же значит создать объект?
Создание объекта – это некий процесс обращения к конкретному экземпляру описанного объекта. После описания объекта он имеет некую абстрактную форму и когда мы обращаемся к какому-то конкретному работнику, к какому-то конкретному экземпляру этого описания: работник 1, работник 2, работник 3. У нас может быть множество работников, которые соответствуют этой схеме.
Когда мы с вами обращаемся к какому-то конкретному экземпляру этой сущности работника, то мы создаем некий объект, т.е. некий экземпляр существующего описания этого объекта.
Тот программный код, который содержит описательную часть объекта, он называется класс. Часть, в которой мы описываем объект – это называется классом. Т.е. класс – это некая сущность, которая описываем, что будут собой представлять все те экземпляры, которые будут создаваться из этого класса.
Экземпляры классов = объекты.
Объект – это просто что-то конкретное, а класс – это некое абстрактное понятие, которое просто содержит описательную часть.
Класс – это что-то вроде чертежа объекта, т.е. прежде чем мы создадим какую-то деталь, проектировщик должен сделать ее чертеж. Написать, что у этой детали будут такие-то свойства (высота, ширина, длина). Когда чертеж будет выполнен, мы отдаем его какому-то мастеру, и он уже создает экземпляры из этого класса. Деталей, которые могут быть созданы из этого чертежа огромное количество.
Также и в программировании: класс у нас один, а экземпляров этого класса, объектов может быть огромное количество.
И нужно понимать, что
Чертеж НЕ равно деталь
Класс НЕ равно объект
Общий алгоритм работы с объектно-ориентированным подходом в программировании:
Конечно, сейчас многое может быть с этим не понятно, но здесь важно приступить к практике и посмотреть на конкретных примерах, как это работает.
JavaScript: полное руководство по классам
Доброго времени суток, друзья!
В JavaScript используется модель прототипного наследования: каждый объект наследует поля (свойства) и методы объекта-прототипа.
Классов, используемых в Java или Swift в качестве шаблонов или схем для создания объектов, в JavaScript не существует. В прототипном наследовании есть только объекты.
Прототипное наследование может имитировать классическую модель наследования от классов. Для этого в ES6 было представлено ключевое слово class: синтаксический сахар для прототипного наследования.
В данной статье мы научимся работать с классами: определять классы, их частные (приватные) и открытые (публичные) поля и методы, а также создавать экземпляры.
1. Определение: ключевое слово class
Для определения класса используется ключевое слово class:
Такой синтаксис называется объявлением класса.
Класс может не иметь названия. С помощью выражения класса можно присвоить класс переменной:
Классы можно экспортировать в виде модулей. Вот пример экспорта по умолчанию:
А вот пример именованного экспорта:
Классы используются для создания экземпляров. Экземпляр — это объект, содержащий данные и логику класса.
Экземпляры создаются с помощью оператора new: instance = new Class().
Вот как создать экземпляр класса User:
2. Инициализация: constructor()
В следующем примере конструктор устанавливает начальное значение поля name:
Конструктор принимает один параметр — name, который используется для установки начального значения поля this.name.
this в конструкторе указывает на создаваемый экземпляр.
Аргумент, используемый для создания экземпляра класса, становится параметром его конструктора:
Параметр name внутри конструктора имеет значение ‘Печорин’.
Если не определить собственный конструктор, будет создан стандартный конструктор, представляющий собой пустую функцию, не влияющую на экземпляр.
3. Поля
Поля класса — это переменные, содержащие определенную информацию. Поля могут быть разделены на две группы:
3.1. Открытые поля экземпляров класса
Выражение this.name = name создает поле экземпляра name и присваивает ему начальное значение.
Доступ к этому полю можно получить с помощью аксессора свойства:
В данном случае name — открытое поле, поскольку оно доступно за пределами класса User.
При неявном создании полей внутри конструктора, сложно получить список всех полей. Для этого поля нужно извлекать из конструктора.
Лучшим способом является явное определение полей класса. Неважно, что делает конструктор, экземпляр всегда имеет одинаковый набор полей.
Предложение по созданию полей класса позволяет определять поля внутри класса. Кроме того, здесь же можно присваивать полям начальные значения:
Изменим код класса User, определив в нем открытое поле name:
Такие открытые поля являются очень наглядными, быстрый взгляд на класс позволяет понять структуру его данных.
Более того, поле класса может быть инициализировано в момент определения:
На доступ к открытым полям и их изменение нет ограничений. Читать и присваивать значения таким полям можно в конструкторе, методах и за пределами класса.
3.2. Частные поля экземпляров класса
Инкапсуляция позволяет скрывать внутренние детали реализации класса. Тот, кто использует инкапсулированный класс, опирается на публичный интерфейс, не вдаваясь в подробности реализации класса.
Такие классы проще обновлять при изменении деталей реализации.
Хорошим способом скрыть детали является использование частных полей. Такие поля могут быть прочитаны и изменены только внутри класса, которому они принадлежат. За пределами класса частные поля недоступны.
Для того, чтобы сделать поле частным, перед его названием следует поставить символ #, например, #myPrivateField. При обращении к такому полю всегда должен использоваться указанный префикс.
Сделаем поле name частным:
#name — частное поле. Доступ к нему можно получить только внутри класса User. Это позволяет сделать метод getName().
Однако, при попытке получить доступ к #name за пределами класса User будет выброшена синтаксическая ошибка: SyntaxError: Private field ‘#name’ must be declared in an enclosing class.
3.3. Открытые статические поля
В классе можно определить поля, принадлежащие самому классу: статические поля. Такие поля используются для создания констант, хранящих нужную классу информацию.
Для создания статических полей используется ключевое слово static перед названием поля: static myStaticField.
Добавим новое поле type для определения типа пользователя: администратора или обычного. Статические поля TYPE_ADMIN и TYPE_REGULAR — константы для каждого типа пользователей:
Для доступа к статическим полям следует использовать название класса и название свойства: User.TYPE_ADMIN и User.TYPE_REGULAR.
3.4. Частные статические поля
Иногда статические поля также являются частью внутренней реализации класса. Для инкапсуляции таких полей можно сделать их частными.
Для этого следует перед названием поля поставить префикс #: static #myPrivateStaticFiled.
Предположим, что мы хотим ограничить количество экземпляров класса User. Для сокрытия информации о количестве экземпляров можно создать частные статические поля:
Статическое поле User.#MAX_INSTANCES определяет допустимое количество экземпляров, а User.#instances — количество созданных экземпляров.
Эти частные статические поля доступны только внутри класса User. Ничто из внешнего мира не может повлиять на ограничения: в этом заключается одно из преимуществ инкапсуляции.
Прим. пер.: если ограничить количество экземпляров одним, получится интересная реализация шаблона проектирования «Одиночка» (Singleton).
4. Методы
Поля содержат данные. Возможность изменять данные обеспечивается специальными функциями, являющимися частью класса: методами.
JavaScript поддерживает как методы экземпляров класса, так и статические методы.
4.1. Методы экземпляров класса
Методы экземпляра класса могут изменять его данные. Методы экземпляра могут вызывать другие методы экземпляра, а также статические методы.
Например, определим метод getName(), возвращающий имя пользователя:
В методе класса, также как и в конструкторе, this указывает на создаваемый экземпляр. Используйте this для получения данных экземпляра: this.field, или для вызова методов: this.method().
Добавим новый метод nameContains(str), принимающий один аргумент и вызывающий другой метод:
nameContains(str) — метод класса User, принимающий один аргумент. Он вызывает другой метод экземпляра getName() для получения имени пользователя.
Метод также может быть частным. Для того, чтобы сделать метод частным следует использовать префикс #.
Сделаем метод getName() частным:
#getName() — частный метод. Внутри метода nameContains(str) мы вызываем его так: this.#getName().
Будучи частным, метод #getName() не может быть вызван за пределами класса User.
4.2. Геттеры и сеттеры
Геттеры и сеттеры — это аксессоры или вычисляемые свойства. Это методы, имитирующие поля, но позволяющие читать и записывать данные.
Геттеры используются для получения данных, сеттеры — для их изменения.
Для установки запрета на присвоение полю name пустой строки, обернем частное поле #nameValue в геттер и сеттер:
4.3. Статические методы
Статические методы — это функции, принадлежащие самому классу. Они определяют логику класса, а не его экземпляров.
Для создания статического метода используется ключевое слово static перед названием метода: static myStaticMethod().
При работе со статическими методами, следует помнить о двух простых правилах:
isNameTaken() — статический метод, использующий частное статическое поле User.#takenNames для определения использованных имен.
Статические методы также могут быть частными: static #myPrivateStaticMethod(). Такие методы могут вызываться только внутри класса.
5. Наследование: extends
Классы в JavaScript поддерживают наследование с помощью ключевого слова extends.
В выражении class Child extends Parent < >класс Child наследует от класса Parent конструктор, поля и методы.
Создадим дочерний класс ContentWriter, расширяющий родительский класс User:
ContentWriter наследует от User конструктор, метод getName() и поле name. В самом ContentWriter определяется новое поле posts.
Обратите внимание, что частные поля и методы родительского класса не наследуются дочерними классами.
5.1. Родительский конструктор: super() в constructor()
Для того, чтобы вызвать конструктор родительского класса в дочернем классе, следует использовать специальную функцию super(), доступную в конструкторе дочернего класса.
Пусть конструктор ContentWriter вызывает родительский конструктор и инициализирует поле posts:
super(name) в дочернем классе ContentWriter вызывает конструктор родительского класса User.
Обратите внимание, что в дочернем конструкторе перед использованием ключевого слова this вызывается super(). Вызов super() «привязывает» родительский конструктор к экземпляру.
5.2. Родительский экземпляр: super в методах
Для того, чтобы получить доступ к родительскому методу внутри дочернего класса, следует использовать специальное сокращение super:
getName() дочернего класса ContentWriter вызывает метод getName() родительского класса User.
Это называется переопределением метода.
Обратите внимание, что super можно использовать и для статических методов родительского класса.
6. Проверка типа объекта: instanceof
Выражение object instanceof Class определяет, является ли объект экземпляром указанного класса.
Оператор instanceof полиморфичен: он исследует всю цепочку классов.
Что если нам нужно определить конкретный класс экземпляра? Для этого можно использовать свойство constructor:
7. Классы и прототипы
Надо сказать, что синтаксис классов — это хорошая абстракция над прототипным наследованием. Для использования классов не нужно обращаться к прототипам.
Однако, классы являются лишь надстройкой над прототипным наследованием. Любой класс — это функция, создающая экземпляр при вызове конструктора.
Следущие два примера идентичны.
Поэтому для понимания классов требуется хорошее знание прототипного наследования.
8. Доступность возможностей классов
Возможности классов, представленные в данной статье, распределены между спецификацией ES6 и предложениями, находящимися на третьей стадии рассмотрения:
Прим. пер.: по данным Can I use поддержка частных полей классов на сегодняшний день составляет 68%.
9. Заключение
Классы в JavaScript используются для инициализации экземпляров с помощью конструктора, определения их полей и методов. С помощью ключевого слова static можно определять поля и методы самого класса.
Наследование реализуется с помощью ключевого слова extends. Ключевое слово super позволяет получить доступ к родительскому классу из дочернего.
Для того, чтобы воспользоваться преимуществами инкапсуляции, т.е. скрыть внутренние детали реализации, сделайте поля и методы частными. Названия таких полей и методов должны начинаться с символа #.
В современном JavaScript классы используются повсеместно.
Надеюсь, статья была вам полезной. Благодарю за внимание.
Objective-C как первый язык программирования
Данный пост был задуман после того, как на некоторые важные вопросы не было найдено внятных ответов. Я отнюдь не претендую на то, что стал крутым программистом. Нет, всё ещё впереди, но период высиживания уже пройден. Это статья из цикла «Не умеешь сам — научи другого». В смысле, чтобы что-то лучше понять нужно это что-то, кому-то объяснить. Мопед не мой, эта фраза встречалась мной раньше в публикациях на Хабре. Некоторые вещи очень сложно понять. И люди, которые понимают, обычно не могут объяснить начинающему. Может быть меня тоже это ждёт. Это как разговор взрослого и ребёнка. Практически конфликт поколений. Пока мой уровень не перерос в профессионала, нужно изложить моё текущее видение.
В статье, термины которые используются при объяснении различных понятий взяты в кавычки. Статья написана для людей, которые уже научились отличать циклы от массивов и понимают что такое функция и метод.
Если Вы, никогда не программировали, то книга Кернигана и Ритчи (в любом издании), Вам явно будет не по силам. В природе не существует такой силы воли, которая смогла бы заставить Вас дочитать книгу до конца, при этом решить все приведённые задачи.
Очень рекоммендую BecomeAnXcoder. Там всё написано достаточно понятно для людей, которые о программировании знают крайне мало. Информация немного устарела, но для старта сойдёт. Может она Вам уже попадалась на глаза или вы даже скачали её, но отложили в каталог с литературой (ну такой каталог есть у каждого, он занимает десятки гигабайт и всё это мы собираемся прочитать как только появится свободное время, а каталог всё растёт. ).
Понятно, что оптимальный вариант — MAC. На худой конец — Хакинтош или виртуальная машина. И даже если процессор не позволяет запустить ничего из вышеизложенного — начать можно прямо в блокноте с последующей компиляцией в коммандной строке.
На многих форумах можно найти популярный вопрос, задаваемый людьми, которые, по-видимому находятся в тяжело-бронированном танке: «Нужно ли программисту Objective-C учить собственно С?». Везде пишут одно и то же. Те кто побородатее и начинали со структурного программирования — говорят, что просто необходимо стать, как минимум MiddleDeveloper’ом в C, и лишь потом искать путь в лютых дебрях ООП, коим является Objective-C. Те кто не знал С, но уже каким-то образом достиг статуса MiddleDeveloper’а, возражают: мол, выучи как кнопки на iPhone рисуются и как им назначить функцию, а матчасть — потом подтянется, по мере необходимости. Категорически заявляю, что выучить как кнопкам назначаются функции, не есть программирование! Я не призываю потратить полгода на понимание чистого С. Но пару недель — месяц уделить стоит. Это даст некоторый бэкграунд Вашим амбициям. По мере обучения уже Objective-C обязательно будут возникать такие структуры кода, что не будет ничего понятно. Поэтому, предлагаю безо всякого фанатизма, но детально ознакомиться с книгой Крупника А.Б. «Изучаем Си». Она раза в 3 больше предыдущей по объему, но читается легко и непринуждённо. В книге опять же, на достаточно доступном уровне, объясняются основные азы программирования. В ней можно узнать как отличить массив от цикла и что такое указатели.
Недавно на Хабре промелькнула статья, где автор приводил кучу литературы, которую советовал прочитать и пойти работать джуниором за хлеб. Если Вы просто прочитаете всю приведенную в той статье литературу, то ничему не научитесь, а если вы сможете перерешать и запомнить опять же всю литературу, то Вам можно будет идти не джуниором, а солидным разработчиком.
Начало: метод класса и метод экземпляра
Что такое метод? Это набор команд/инструкций или одна команда/инструкция, которая может быть применена к объекту и вызывает в нём необходимые процессы. Если так не совсем понятно, то читайте дальше и поймёте. На самом деле тяжело понять что такое метод класса и метод экземпляра. Все говорят: «со знаком „+“ — это метод класса, а вот со знаком „-“ — это метод экземпляра. Понятно?» И в ответ слышат: «Да-а, метод класса и метод экземпляра». Я лично сначала понимал только то что они разные, а вот что и когда применять — осталось не понятным. Википедия упорно повторяет то же самое, что мы слышали и читали.
В подавляющем большинстве случаев, Вы будете работать с методами экземпляра.
Итак, метод экземпляра. Представим, что у нас есть программа, в которой мы будем использовать 2 класса: Primus и Kitchen.
Любой класс (кроме абстрактного) имеет методы и/или функции. Класс может иметь несколько методов со знаком «+» перед названием метода (метод класса) и несколько методов со знаком «-» перед названием метода (метод экземпляра). Вот те методы, которые со знаком «-» мы активно применяем в отношении объектов — экземпляров класса и собственно класса. А методы со знаком «+» можно применять только в отношении самого класса, где этот метод был объявлен.
Что такое экземпляр класса?
Звучит гордо, но непонятно. Кто помнит из школьного курса: в геометрии точка — родитель для круга, прямой и прочих фигур, потому что каждая фигура состоит из множества точек.
Класс для Objective-C, на некоторых ресурсах интерпретируют как объект и наоборот. На самом деле это немного на так. Можно сказать что объект это экземпляр класса. Как конкретный экземпляр стоящего у Вас на кухне примуса — это экземпляр типа «Примус»: с крутилками, горелкой и пр. Это не просто примус — это Ваш примус. Класс — это пример для подражания. Образец-эталон чего-то, что тоже может исполнять некоторые функции благодаря методам класса (со знаком «+»). Вот здесь можно прочитать немного более развёрнуто.
Также есть «протоколы» и «абстрактные классы». Здесь всё более интересно, но порог понимания выше чем у класса и объекта. Различие состоит в том, что «протокол» не может иметь подкласс или дочерний объектно его на наследуют, ему нужно соответствовать. Как требованию при приёме на работу. Применение протоколов в реальной жизни я затрону в этой статье. Абстрактный класс — это такая сущность, которая как бы класс, но не совсем конкретный класс, потому и абстрактный. Например опять же, Ваш домашний примус — он экземпляр класса «Примус», а не какого-то абстрактного класса «Нагревательный прибор». Вы же не можете иметь дома нагревательный прибор без рода и племени (это может быть также камин и батарея). Вот таким образом, класс «Примус» — может быть наследником абстрактного класса «Нагревательный прибор». А уже Ваш примус — экземпляр конкретного определения примуса. И за своими атрибутами — свойствами, методами, протоколами он при использовании обращается к своему классу и сверяет что он может делать что не может и что он вообще может иметь в наличии.
Представим что есть некий класс «Горелка газовая» — наследник абстрактного класса «Нагревательный прибор». Класс «Горелка газовая» будет родительским для «Примуса» и «Газовой плиты». Для того, чтобы приблизиться к программированию, нужно немного абстрагироваться.
В Objective-C есть родительский класс NSObject. В языке программирования он как точка в геометрии. Это идеальный класс: в нём нет ничего лишнего, он ничего конкретного делает, но из него можно создать всё что угодно. Такой вот кирпичик мироздания. Если в Xcode зажать кнопку «Command» и кликнуть на NSObject, то перед Вами откроется содержимое файла NSObject.h. В нём около 200 строк описания различных методов. Есть как методы со знаком «+» перед названием, а также методы со знаком «-«. Суть методов со знаком «+» такова что их можно применить только непосредственно к самому NSObject. Таким методом является, например,
и применять его можно только так:
Любой другой объект в Objective-C по определению — потомок NSObject. В нём реализовываются дополнительные методы, которые придают ему черты индивидуальности. Допустим это NSResponder. У этого потомка — NSResponder’а тоже могут быть дочерние объекты. К примеру UIView. Далее по древу наследования можно в качестве примера взять UIScrollView. Потом — UITableView. В каждом случае потомки обрастают дополнительным функционалом. Кроме того, что они умеют делать что-то своё, индивидуальное, они могут делать всё то что может делать их предок. Это и есть — наследование.
Если же вы не хотите, чтобы Ваш класс-потомок абсолютно точно копировал поведение класса-родителя, то можно переделать любой метод класса — родителя по Вашему вкусу. Это есть — полиморфизм.
В Ваших программах вы будете брать нужный Вам класс и добавляя в него нужные методы — расширять его функционал. Также можно брать созданный Вами класс и делать его потомка, опять же расширяя функционал и одновременно создавая уникальный инструмент, для решения нужной задачи. Описанный механизм называется — создание подклассов «subclass».
Не буду вдаваться в широкие описания методов со знаком «+». Нагляднее будет показать, что применение метода
к любому классу или подклассу выделяет под него нужный объём памяти в ОЗУ компьютера.
инициализирует объект, выделяет для него место в ОЗУ и собственно после этого объект начинает существовать и с ним можно работать.
Эти 2 метода («alloc» и «init») только что создали объект «object». И данный объект является экземпляром объекта или экземпляром класса NSObject. Если применить эти методы по раздельности
то объект тоже будет создан. Но есть ненулевая вероятность того Вы создадите не тот объект, которому выделили память. Допустим, вызов метода
выделил для него такой адрес в памяти
Так происходит потому что при инициализации, исполняемая среда, всем объектам задаёт значение «nil», чтобы избежать ссылки на место в памяти, заполненное «мусором». Или ссылки на другой конкретный объект, который по факту тоже уже является «мусором», потому что он закончил свой жизненный цикл и уже не «хранится» в памяти, а просто «находится». Для того чтобы понять что такое «мусор», создайте простейшую программку, в которой объявите
не присваивая ей значение, а потом выведите её значение в консоль
Вы будете удивлены тем, чему равняется Ваше «i».
Также будет создан экземпляр объекта «isa», который будет рассмотрен позже. Это единственный ненулевой указатель при создании Вашего объекта. Допустим, это ниточка к родительскому объекту, который породит свой экземпляр и даст жизнь нашему объекту.
То есть теоретически объект уже есть после применения метода «alloc». Но он не сможет пройти проверку
Такой кусок кода можно видеть в любом шаблонном объекте в методе «init» или его производных.
В данном случае, объект вроде как есть, но в принципе он равен «nil». Не инициализированный объект — это как машина, которую Вы только собираетесь купить в кредит. Вроде как есть, но она не Ваша. И если не отходя от кассы применить метод «init»
то «Бинго!», и объект принадлежит Вам, с ним можно делать всё что хотите. А вот если к нему применить метод
то инициализироваться может другой объект. Вроде как вы выплатили кредит за машину, но оказалось что не за ту машину и Вам вместо одного автомобиля дают другой. Они на первый взгляд не отличимы друг от друга. Но у них разные «VIN» номера, а значит при проверке на посту «ГАИ» Вам сообщат что авто не Ваш. Ниже будет приведено дополненное объяснение этого явления.
Как Вы уже поняли метод «+alloc» — метод класса, а метод «-init» — метод экземпляра.
Приведу пример с реальными вещами.
Полная реализация метода включает в себя обычно 2 файла с расширениями *.h и *.m. Бывает и другое количество, в зависимости от того, что это за класс и какие цели он преследует.
В Вашей программе есть класс «Primus». В файле «Primus.h» объявлены методы:
Также в программе есть класс «Kitchen», где в файле «Kitchen.h», объявлены методы:
В файлах «Primus.m» и «Kitchen.m» все объявленные методы должны быть реализованы, то есть описаны: как и что в каждом методе происходит.
Если вы собираетесь в каком-либо классе создавать экземпляр объекта другого класса, то в шапке нужно будет импортировать файл *.h создаваемого объекта, например в шапке файла Kitchen.h мы впишем
Для начала создадим экземпляр класса «Primus» внутри класса «Kitchen»
Как видите, мы посылаем метод c «+» не экземпляру класса «myPrimus», а непосредственно классу «Primus». Экземпляр класса «Primus» под названием «myPrimus» создан. В дальнейшем, методы из «Primus.h» со знаком «-» будут применяться к экземпляру класса — «myPrimus». И если захотим создать новый экземпляр класса «Primus», то можно будет опять воспользоваться методом «+hotAsHell». Также в классе «Primus» есть метод
Обычно все методы, название которых начинается с «init», делают то же самое что и метод «init» класса NSObject, только с расширенными возможностями. И в данном случае применение метода «init» в таком ракурсе
создаст новый объект класса «Primus» с уникальными характеристиками.
В описанном только что примере был применён метод с аргументами. В данном, конкретном случае, он применяется для создания экземпляра класса «Primus» с чётко заданными характеристиками. По названию характеристик видно, что данный экземпляр класса «Primus» будет работать на газе типа «Propan» и при температуре 750 градусов.
Обратите внимание, что названия методов в Objective-C весьма осмысленны. Временами Вы будете поражены их названиями состоящими из 10 слов, но это способствует лучшему понимаю написанного. Грубо говоря код получается самодокументируемым. Что конечно же не исключает необходимости написания комментариев. Но если взять за правило создавать свои методы, название которых будет нести смысловую нагрузку и таким же образом относиться к созданию переменных, то количество комментариев в коде можно заметно снизить.
В отличие от некоторых других языков программирования в Objective-C методы не вызываются, а посылаются объектам. Таким образом, этот ЯП относится к «message oriented language», на русском языке звучит не так строго, поэтому перевод не привожу.
Также обратите внимание на то, что все методы которые после посылки объекту создают (возвращают) новый объект имеют в скобочках после «+» или «-» либо конкретное название объекта, экземпляр которого они будут возвращать, либо «id». То есть, по том, какой объект указан в скобочках сразу после знака «+» или «-«, можно судить что мы получим после посылки этого метода. Что такое «id»? Это такой тип объекта, который может принимать форму (тип) любого другого объекта. Скажем это «слабый» тип объекта. Не в смысле того, что ему что-то «слабо». Если говорить общепринятыми понятиями, то это слабо типизированный объект. Наличие таких объектов в ЯП делает его слабо типизированным.
Также можно в этих самых скобочках обнаружить тип «void».
Что такое «void»?
Все говорят: «это когда метод ничего не возвращает». А зачем же он нужен? Применение метода этого типа всё же производит манипуляции с объектами, структурами и цифрами. Также объекты и скалярные величины, попавшие в него в качестве аргументов могут измениться либо вообще исчезнуть. Всё зависит от того, что реализовано внутри каждого конкретного метода. Дело в том, что «void» таки ничего не возвращает… нового. Как и было сказано, то что попавшие в него аргументы могут изменяться сами, либо влиять на другие объекты, манипуляция с которыми производится в методе с «void». Он может даже создавать новые объекты внутри себя, но наружу ничего не возвращается в явном виде. Обычно метод, который возвращает что-то, имеет ключевое слово «return» в самом конце. А метод типа «void», «return» в конце не имеет. Он может его иметь внутри своих собственных циклов или условий, чтобы иметь возможность прервать их в нужном месте. Но не в конце. Метод не создаёт ничего принципиально нового, он просто, работая с указателем на какой-то объект (число, массив, ячейка и т.д.), меняет данные по этому адресу или применяет их для расчёта других данных, которые присваивает другим объектам.
Что такое «self»?
Это слово очень часто применяется где попало. Сам факт его применения во всевозможных местах, вносит путаницу в стройные кладовые Ваших знаний.
Вернёмся к классам «Primus» и «Kitchen». Возьмём конкретный метод класса «Primus» и рассмотрим как будет выглядеть его реализация в файле «Primus.m». Например это метод.
может быть реализован таким образом:
В фигурных скобках происходит реализация или «имплиментация» метода. В данном случае, реализация метода читается так: если не myPrimus, то выполнить команду
которая в свою очередь читается как: себе инициализировать с газом:gas температурой:750. То есть, метод посылается себе, а не какому-нибудь другому объекту. В данном случае «себе» — это классу «Primus», так как метод находится внутри класса «Primus». Его объявление — в файле Primus.h и реализация в файле Primus.m.
Также можно заметить, что метод ничего не возвращает «void». То есть получается каламбур: если примуса нет, то мы его создаём, но наружу он из метода не выходит. Зачем его тогда создавать? Допустим его функционал реализован так:
И тут уже понятно что где-то внутри метода появляется мастер по ремонту примуса.
Почему был использован знак восклицания «!» в скобках после «if»? В программировании это — знак отрицания. То есть «!=» звучит как «не равно». Этот способ условия удобен своей лаконичностью. В данном примере можно было использовать другое по структуре условие, которое несло бы ту же самую функцию.
Это условие имеет в 2 раза большую длину и нужно полностью читать всю строку, чтобы понять его. Это условие небольшое, но если Вам нужно записать что-то вроде этого
будет в более выигрышной позиции, как по лаконичности так и по физическому размеру. Предыдущая конструкция — банально может просто не влезть в одну строку.
Рассмотрим как выглядела бы реализация этого метода в рамках класса «Kitchen». В файле «Kitchen.m» тот же метод будет реализован так:
Видно, что здесь нужно указать, какой объект будет создаваться, как будет называться его экземпляр и потом непосредственно родительскому классу посылать метод.
То есть, хитрое слово «self», применяется внутри класса, как будто вы уже создали его экземпляр.
и обращаетесь к экземпляру класса. Только фишка в том, что вы ничего не создавали, и обращаетесь не к экземпляру, а напрямую к классу. Для наглядности я создал объект
к которому можно обратиться с методом. Но можно было его не создавать, а реализовать более сложную структуру, которая выполняла бы те же самые функции
Для того, чтобы понять можно ли написать «self» или нельзя — просто представьте себе какой метод какому объекту Вы хотите послать и начните вводить слово «self», но не до конца, например «sel». Xcode предложит несколько вариантов, среди которых будет собственно «self». Слева от него будет описание — какой это класс. Если это именно тот класс, которому вы хотели послать нужный метод (класс внутри которого вы сейчас производите действие), значит используйте «self». Если Xcode указывает, что «self» это не тот объект, который Вам нужен — то используйте имя класса или экземпляра нужного Вам.
Также видно что здесь были задействованы аргументы. У каждого аргумента есть тип, который тоже описан в скобках, но после двоеточия. После скобок с типом аргумента идёт имя аргумента. Если в скобках присутствует знак «*» после типа аргумента, то это объект. Если знака «*» нет, то это скалярный тип, например «NSInteger», который по сути является простым «int». Также «NSInteger» может быть со знаком «*» для передаваемого аргумента. В таком случае мы будем передевавать не саму переменную, а указатель на неё. Тема Указателей выходит за рамки данной статьи. Имя аргумента, в данном методе
будет звучать как «gas». Вы обратили внимание, что в реализации не было использовано нормального названия газа? Например «Propan». Дело в том, что в аргументе «gas» как раз и передаётся нужное название газа. Откуда? Мы рассмотрели как реализовуется метод
В нём был задействован метод
В этом методе было 2 аргумента «gas» и «t». В посылке метода объекту, температуру мы указали, а тип газа просто продублировали от метода
То есть этот метод тоже где-то посылается. Рассмотрим поближе метод
Его реализация может выглядеть так
Обратите внимание на значение посылаемого аргумента «propanButan». Именно оно передаётся по всему классу, от метода к методу.
Также здесь видно что метод посылается объекту при определённых условиях.
Нужно знать что ни один Ваш метод сам по себе не может сработать. Ему нужен «пинок» снаружи. Нажатие кнопки, возникновения какого-либо события или его должен запустить метод протокола, который среда исполнения запускает в нужный ей момент. Данный метод «hotAsHell» посылается лишь после явного вызова, это не системный метод, он тоже где-то должен быть прописан либо чему-то назначен.
Теперь рассмотрим метод
Он состоит из типа возвращаемого объекта, типов аргументов, аргументов и селектора. Селектор это то что остаётся от метода когда от него отнять тип возвращаемого объекта, тип аргументов, и аргументы.
именно с двоеточиями. Если аргументов нет, то двоеточий тоже нет, как в случае с «hotAsHell». Часто прийдётся сталкиваться с необходимостью употребить селектор. Теперь вы знаете что употреблять.
Немного выше было использовано понятие «super».
Что такое «super»?
Рассмотрим реализованный выше метод «hotAsHell». В нём есть такая конструкция
Так принято инициализировать дочерний класс — через инициализацию родительского.
Предположим, что класс «Primus» — непосредственный потомок класса «NSObject». Именно тот класс, который стоит по иерархии сразу над тем классом, с которым мы работаем имеет право называться «super». Команда
вызывает метод init экземпляра NSObject. То есть, автоматически создаётся экземпляр прародителя всех объектов — NSObject, с дефолтными (сугубо NSObject’овскими) параметрами. Посылка метода «init» NSObject’y возвращает «self» от NSObject’a. То есть непосредственно экземпляр самого NSObject’a. И этот экземпляр присваивается нашему объекту «Primus». Ведь «self» в данном случае — является именно «Primus’ом». И мы на данном этапе получаем экземпляр объекта «Primus», который ничем не отличается от NSObject’а. Индивидуальные черты ему придаёт наша посылка метода
а также остальные методы, реализованные в рамках данного класса.
Конструкция
это просто перестраховка на случай, если что-то пойдёт не так и дефолтный «Primus» не создастся. т.е. метод init класса родителя не выполнится. В таком случае обычно делают
где пытаются исправить положение дел, но, к сожалению, это не тот случай и «else» нам уже ничем не поможет.
И здесь я хочу Вам напомнить о неинициализированном объекте из начала статьи. Именно при инициализации экземпляра объекта его суперклассом, происходит назначение места в памяти ему и передача указателя на это место в памяти. И когда проводим проверку
то именно в этот самый момент «self» может получить неожиданный адрес в памяти. То есть, полученный указатель уже будет не «self». Суперкласс не возвратит нам что-то из ряда вон выходящее. Экземпляр объекта будет идентичен тому с которым мы собираемся работать. Но экземпляр именно этого объекта не будет тем экземпляром, который нам нужен. Это настолько редкая ошибка, что Вы можете её не наблюдать очень продолжительное время в своих приложениях. Просто в один прекрасный момент Ваше приложение может начать выдавать экзотические ошибки. Вследствие чего придётся потратить время на то, чтобы найти их причину. Выделенная память под Ваш объект не была задействована. Инициализироваться мог случайный указатель, не имеющий никакой связи в объектом, которому была выделена память методом «alloc». Вот тогда «self» не проходит проверку
В рассматриваемом методе инициализации. И всё потому что в каком-то месте программы при вызове этого объекта инициализация не была произведена должным образом.
Последнее, что мы должны сделать для завершения инициализации
Поскольку данный метод не «void», то он ожидает от нас, что в конце мы скажем ему что нужно возвратить. В данном случае будет возвращён объект типа «Primus», потому что «self» в рамках данного класса — именно «Primus». Также тип возвращаемого объекта нам говорит о том что ожидается именно «Primus».
В этих методах
тип возвращаемых объектов — «Kitchen», «UkrainianBorsch» и «MasterPoRemontu».
Таким образом, в методе «hotAsHell» мы говорим, что в конце выполнения данного метода желаем получить объект типа «Primus» с заданными параметрами.
Какими именно заданными параметрами?
Опишем такую реализацию метода
Это значит, что при вызове этого метода
задаются буквально такие параметры
Параметры задаются переменным, которые объявлены в файле *.h
Обратите внимание на конструкцию слова «setGas» или «setTemperature». Если есть переменная, например «variable», то задать ей нужное значение можно через префикс «set»:
при этом первая буква переменной становится заглавной. Таким образом, мы выяснили что в файле Primus.h были объявлены переменные «gas» и «temperature». Но само наличие переменных не даёт нам возможности назначать их с помощью префикса «set»
Для получения такой возможности нужно объявить свойства для этих переменных. Допустим такие:
а в файле имплементации нужно будет прописать
и только после этого станет возможным присвоение им значения через «setGas» и «setTemperature». Эти префиксы называются сэттерами.
В любой удобный момент можно попросить объект «Primus» показать Вам эти значения, обращаясь к его экземпляру
например для команды
Эти методы называются гэттерами. В случае обращения за значениями к названию переменной, ничего дописывать не нужно.
Обратите внимание, что к свойству объекта можно обращаться как через конструкцию
Они выполняют аналогичные действия.
Есть одна хитрость при доступе к переменным объекта. Это можно производить не только через свойства, но и через доступ к ним по принципу ключ-значение «key-value coding». То есть можно обратиться к переменной
Мы обратились за значением, которое находится в объекте «Primus» в ключевом слове «gas».
А такая конструкция
в контексте «key-value coding» будет выглядеть так
Вместо свойств использовать «key-value coding» — вполне нудное занятие. Но иметь понятие о нём необходимо, чтобы в случае, когда без этого не обойтись — воспользоваться.
Также не лишним будет указать тот факт, что с недавнего времени пременными в программировании на Objective-C уже не пользуются. Вместо них используют свойства. Свойства могут быть как доступными извне, так и инкапсулированными. Естественно, что для использования внутри методов можно и нужно использовать переменые. Но объявляние переменных в блоке «ivar», который находится в интерфейсе класса — это уже анахронизм.
runtime
Даже если этого ещё не произошло, есть вероятность того что вскоре Вы встретите в документации слово «runtime» и в пределах той же статьи слово «isa».
Понятие «runtime» можно охарактеризовать как «среда в которой происходит перевод Вашего кода на более низкоуровневый код». «runtime» написан непосредственно с использованием C и Ассемблера. Это ещё не перевод в машинный код, а приведение Вашего кода к языкам C и Ассемблеру. Ваш метод
в «runtime» на С выглядит примерно как
Этого для начинающего Cocoa программиста должно быть достаточно, чтобы понять: дальше лучше в дебри не лезть. Как только Вы перейдёте порог вхождения в клуб, то сами сможете отыскать нужную Вам информацию.
Пока же нас интересует что такое «isa».
Это переменная, которая объявлена непосредственно в NSObject’е. Единственная его переменная. Когда мы вызывали метод
то создавался не только экземпляр класса NSobject, но и экземпляр этой переменной «isa», которая ссылается на NSObject. То есть, она конкретно говорит «runtime’у», что она принадлежит объекту NSObject. А значит, и работать с экземпляром Вашего, только что созданного объекта нужно как и с NSObject’ом. В «isa» записывается указатель на тот родительский объект, который нам нужно унаследовать. Допустим, Ваш объект — потомок NSArray или UITableView или CFDictionaryRef или любого другого объекта. В таком случае «isa» указывает на NSArray или UITableView или CFDictionaryRef или любой другой объект соответственно. Так что создание экземпляра любого объекта, создаёт и переменную класса — «isa», которая ссылается непосредственно на родительский класс, вследствие чего «runtime» знает как будет поступать с каждым экземпляром.
Эта информация на этапе обучения нужна не для чего-то конкретного, а в принципе, для более объёмного понимания философии программирования Objective-C.
В процессе чтения книг и различной документации, на глаза Вам не раз попадётся понятие «singleton». Как говорит один популярный интернет-мем: «Нельзя вот так сразу взять и понять, что такое „singleton“.
Что такое синглтон?
Вообразим себе, что Вам нужно создать объект, который при каждом его вызове в любой точке приложения, возвращает один и тот же экземпляр. На самом деле, в процессе создания приложений, Вам действительно нужно будет такое создавать. Так почему же нельзя создать объект, несколько раз и присвоить ему те же данные через метод „initWithSomething:“ или с помощью сеттеров? Всё дело в работе с памятью и быстродействием, да и с собственно, меньшими затратами времени на написание кода. Памяти всегда мало, и даже когда на iPhone6 поставят 2Гб ОЗУ — её опять-таки будет мало. Создание одного экземпляра объекта, и последующее обращение к нему — экономит ресурсы устройства и ускоряет работу приложения. А ведь каждый хочет, чтобы его приложение было быстрым как „Bugatti Veyron“ и юзабельным как слово „хрен“.
Допустим что наш „Primus“ вполне может быть синглтоном. Тогда его метод
при реализации будет выглядеть так
Рассмотрим что это значит позже. Пока что выясним, зачем „Primus“ делать синглтоном.
Допустим, это не вполне обычный „Primus“, а раритетный. На нём есть гравировка неизвестного мастера, он имеет крайне низкое потребление газа, а также у него есть специальная коробочка, в которой он идеально укладывается. А теперь задайте себе вопрос: „нужен ли Вам другой примус?“. Конечно же нет! Но при посылке метода
будет создан один „Primus“, а при посылке метода
будет создан абсолютно другой „Primus“. Без гравировки и коробочки.
Теперь вернёмся к тому, что написано в реализации метода „hotAsHell“.
Для начала нужно создать экземпляр объекта со свойством „static“, для того, чтобы перекрыть доступ к объекту извне. Затем присвоить ему „nil“, для того чтобы он не взял случайный адрес в памяти. Конструкция
создаёт предикат (условие) — »predicate» который тоже не будет виден извне. Условие заключается в том, что запрещается автоматический или динамический вызов блока, стоящего за предикатом. А вот строка
уже производит все необходимые действия для создания уникального экземпляра объекта. Конкретно «dispatch_once» означает что выражение в скобках после него гарантированно будет запущенно только один раз на протяжении всего жизненного цикла приложения. Также «dispatch_once» гарантирует потокобезопасность. То есть, при запуске приложения в многопоточном режиме эта функция не будет вызвана одновременно в нескольких потоках, и у ж точно не создаст нам ещё один «уникальный „Primus“». Также есть блок
Это вроде маленькой функции или метода. Бывают также большие блоки. В данном блоке происходит инициализация объекта-родителя, после чего его значение присваивается потомку myPrimus.
Вместе вся строка
означает: один раз за весь жизненный цикл приложения будет инициализирован экземпляр объекта «Primus» под названием «myPrimus» со свойствами объекта-родителя и не будет возможности обратиться к этому блоку другим путём. Но о том что был создан «myPrimus» никто не узнает, потому что этот экземпляр объекта снаружи не виден. Все происходит в фоне и только единожды. И происходит благодаря GCD (Grand Central Dispatch). Рассказ о котором — отдельная тема.
И конечно же в конце мы возвращаем созданный синглтон
Синглтон — «Primus» у нас есть, теперь можно добавить ему свойства: коробочка — «Box», гравировка — «Etching», КПД — «Performance». И если объявить для них свойства, то можно будет извне менять эти переменные. Обшить коробочку, почистить гравировку, прочиповать наш «Primus» для повышения КПД. Но это останется наш старый добрый «Primus». Доступ извне к объекту «Primus» будет у тех классов, в шапке которых он объявлен. Но теперь, если делать так
а потом работать с «myPrimus» как с синглтоном, то ничего работать не будет. Все обращения к переменным синглтона должны происходить в следующей манере
так можно создать экземпляр «someBox» совсем другого класса коробок и ему присвоить значение, которое имеет коробка нашего синглтона или наоборот
поменять коробку нашего «Primus».
Синглтон можно применять когда нужно вызвать NSLog с описанием свойств синглтона, а самого синглтона в данном классе нет в принципе. В таком случае его нужно просто объявить в шапке файла и вызвать один раз там где нужно. Синглтон можно и даже рекомендуют использовать в качестве глобальной переменной. Точнее его свойства будут глобальными переменными.
После усвоения основных принципов, можно будет начинать решать предлагаемые в учебниках задачи. И если с написанием своих методов в своих классах и посылкой метода объекту разобраться можно, то в дальнейшем, нужно будет использовать делегаты, протоколы и прочие MVC. Необходимо будет использовать документацию Apple и применять тысячи различных методов, заботливо созданных и описанных купертиновскими программистами.
И тут становится непонятно в принципе как и что работает. Если созданный Вами метод создаёт внутри себя массив, потом вносит в него объекты, потом запускает цикл и что-то в нём делает, а потом этот метод запускает другой Ваш метод, то вроде всё понятно. Но вот Вы открываете документацию по интересующему Вас объекту, а в нём 20 методов, которые могут делать весьма занятные вещи. Кроме того, есть объекты предки, методы которых этот объект тоже может принимать. Кроме того, в начале статьи я писал о протоколах, которым может соответствовать объект. Итого, методов может быть сотни. Какой из них нужно применять? Встречный вопрос: «для чего именно Вам нужен метод?». Правильно заданный вопрос — уже половина ответа. Когда Вы поймёте что хотите сделать, то в описании класса сможете найти интересующий Вас метод и применитьего поназначению. Если Вы хотите чтобы этот экземпляр объекта сделал что-то, присущее только классу от которого он произошёл, то в документации по этому классу нужно внимательно поискать метод, который производит необходимые Вам операции. Послать это метод объекту нужно так
То есть, в документации Вы узнали, что этот метод берёт указанный аргумент «Potato» и делает с ним что-то, что в конечном итоге приводит Вас к цели если применить метод к объекту «myPrimus». Не нужно реализовывать этот метод, он реализован за Вас для прямого применения. Исключения составляют случаи, когда Вам нужно взять готовый класс из фрэймворка и субклассировать его так, чтобы при посылке стандартных методов его экземпляру, происходили нестандартные действия.
Протоколы
Есть также методы протоколов. Как я уже указывал в начале статьи, у них не может быть потомков. Они являются просто набором методов. Для того, чтобы применить метод протокола внутри себя, объект должен соответствовать этому протоколу. Это указывается в файле *.h
В данном случае, объект соответствует сразу двум протоколам «UITableViewDataSource» и «UITableViewDelegate».
И чем отличаются методы классов и протоколов?
Если зайти в описание этих протоколов, то там можно найти методы, которые объект может реализовать. Обратите внимание: методы протоколов Вы не посылаете своему объекту, а должны внутри них указать как должен отреагировать ваш объект, при обращении программы к этим методам. Некоторые методы в протоколах могут быть обязательными. И если вы решили что Ваш объект должен соответствовать протоколу, то обязательные методы нужно реализовать в первую очередь. Внутри любого метода протокола может быть любой метод класса. То есть, метод протокола — это контейнер, в котором находятся любые другие методы, собственно как и любой реализуемый Вами метод. Реализовать необходимый функционал внутри каждого метода протокола нужно исходя из потребностей. К примеру, нужно сделать так, чтобы Ваша формочка делала что-то, при определённых условиях. К примеру, меняла цвет, после того, как стала активной/неактивной. Идём в документацию Apple, смотрим какие протоколы реализуют нужные Вам методы. Затем ищем каким протоколам соответствует родительский класс формочки. Если протоколов, которые поддерживают нужный Вам функционал нет в стандартном наборе функций, то добавляем их в скобках. В описании этих протоколов ищем методы, которые реализуются после какого-либо события. Допустим
который автоматически выполняется когда аргумент «active» принимает значение «YES». И меняет цвет в части экрана описанной в «rect»:
Методы протоколов задают параметры работы экземпляра класса, меняют функционал, передают значения. Например:
возвращает количество строк в секции «section» для заданной таблицы «tableView».
На этом позволю себе закончить. Если статья поможет целевой аудитории, в которой несколько месяцев назад числился и я, то значит, что я думаю правильно и такие статьи нужны. Статьи не профессионалов, а людей, которые понимают что-то на таком уровне, который тяжело перешагнуть, не имея опоры или трамплина. Надеюсь эта статья кому-то будет трамплином или хотя бы табуреткой. Отсутствие хороших учителей, которые могут нормально что-то объяснить — фундаментальная проблема современности. У меня нет педагогического образования, но в статье изложено понятие в программировании в таком ключе, в каком лично мне было бы понятно.





