Сегодня утром я зашел на почту. Нет, не в отделение на углу а в приложение «Почта». Там я случайно открыл письмо годовой давности. Письмо это было от небезызвестной IT-компании из моего города, в котором был представлен список необходимых для вступления в их ряды знаний. Список систематизированный и весьма емкий. Думаю, что если пройтись по нему полностью и изучить все-все-все, то вы не оставите работодателю шансов сказать вам «Нет» =)
В этой новой рубрике мы не спеша и целенаправленно пройдемся по каждому пункту. Каждая новая статья рубрики не будет углубляться в тему до конца, но заложит вам в голову фундамент и понимание темы. В конце каждой статьи вы найдете список материалов, которые вы сможете применить для дальнейшего изучения темы. Так же, в конце каждого раздела вас будет ждать небольшой тест на полученные знания. Итак, приступим!
1. Общая информация:
1.1 ООП
1.3 Паттерны — часть 1 — часть 2
1.5 Использование third-party решений в iOS разработке
Объектно-ориентированное программирование (далее ООП) это парадигма программирования, которая представляет собой понятие «объекты», которые имеют поля данных (атрибуты, описывающие объект) и связанных с ними процедур, известных как методы. Объекты являются, как правило, экземплярами классов, которые используются для взаимодействия друг с другом при создании приложений.
Есть 3 ключевых аспекта ООП:
Инкапсуляция. Объекты должны держать свои данные приватными. Вместо того что бы непосредственно манипулировать данными объекта, другие объекты посылают запросы к объекту в виде сообщений, некоторые из которых объект умеет интерпретировать для изменения своего состояния.
Полиморфизм. Объекты разных классов могут быть использованы как взаимозаменяемые. Это важно, так как позволяет подключать некоторые классы более поздно не обязывая вас предвидеть, когда эти классы были впервые созданы.
Наследование. Объекты одного класса могут вывести часть своего поведения из другого (базового или родительского) класса. В Swift и Objective-C нет множественного наследования, которое есть, например в С++. Наследоваться можно исключительно от одного класса.
Прежде, чем приступить к чтению, обратите внимание на этот замечательный пример ООП, который привел Стив Джобс еще в 1994 году.
ООП: Классы и объекты
В ООП класс представляет собой расширяемый шаблон, состоящий из кода, служащий для создания объектов. Обеспечивает начальное состояние объекта (своих переменных) и реализовывает его поведение (методы, функции). Другими словами — класс подобен плану, определяющему данные и поведение типа.
1 2 | class Button { } |
Только что мы создали пустой класс Button. Давайте теперь создадим объект от него:
1 | var buttonObj = Button() |
В приведенном примере buttonObj является экземпляром класса Button.
ООП: Свойства
У классов и экземпляров могут быть присваиваемые значения, названные свойствами.
1 2 3 | class Square { var length: Int = 1 } |
У класса Square есть свойство length, у которого есть значение по умолчанию 1.
Чтобы создать квадрат с другой длиной (не 1), мы должны создать свой инициализатор.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | class Square { var length: Int = 1 init(length: Int) { self.length = length } } var firstSquare = Square(length: 3) print(firstSquare.length) var secondSquare = Square(length: 1) print(secondSquare.length) if firstSquare.length < secondSquare.length { print("the small square has the length \(firstSquare.length)") } else { print("the small square has the length \(secondSquare.length)") } |
ООП: Методы
Методы добавляют поведение к классам и экземплярам.
1 2 3 4 5 6 7 | class Square { var length: Int = 1 func area() -> Int { return length * length } } |
Метод area() вычисляет область экземпляра Square, когда его вызывают. Вызывать метод можно через точку.
1 2 3 4 5 | var square = Square() square.length = 10 print(square.area()) // prints 100 |
ООП: Свойства класса
Обычно мы используем свойства экземпляра, например: длина Square. У вас могут также быть свойства класса. Ниже приведен пример использования свойств класса. У класса Tank есть вычисленное свойство, названное bonusDamage, который используется, чтобы увеличить повреждение всех tanks при обновлении. Когда обновление завершено, мы должны вызвать callTank.upgrade(), и у всех экземпляров Tank будет больше повреждения.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | class Tank { class var bonusDamage: Double { return Double(Upgrade.level) * 2.5 } let baseDamage = 10.0 var damage: Double { return self.baseDamage + Tank.bonusDamage } class func upgrade() { Upgrade.level += 1 } struct Upgrade { static var level = 0 } } var tank = Tank() print(tank.damage) // 10.0 Tank.upgrade() print(tank.damage) // 12.5 Tank.upgrade() print(tank.damage) // 15.0 |
ООП: Наследование
Класс может наследовать методы, свойства и другие характеристики от другого класса. Когда один класс наследуется от другого, наследующий класс известен как подкласс, и класс от которого наследуется подкласс, известен как его суперкласс. Наследование — фундаментальное поведение, которое отличает классы от других типов.
Простой пример наследования:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | class AClass { func doSomething() { print("Hello from AClass") } } class Subclass: AClass { } let base_object = AClass() base_object.doSomething() //> Hello from AClass let enhanced_object = Subclass() enhanced_object.doSomething() // > Hello from AClass |
ООП: Переопределение
Вы можете переопределить методы, чтобы обеспечить свое поведение. Чтобы переопределить метод, нужно написать ключевое слово override перед объявлением метода:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | class AClass { func doSomething() { print("Hello from AClass") } } class Subclass: AClass { override func doSomething() { print("Hello from Subclass") } } let base_object = AClass() base_object.doSomething() //> Hello from AClass let enhanced_object = Subclass() enhanced_object.doSomething() //> Hello from Subclass |
Вы можете использовать ключевое слово super для вызова метода из суперкласса:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | class AClass { func doSomething() { print("Hello from AClass") } } class Subclass: AClass { override func doSomething() { super.doSomething() print("Hello from Subclass") } } let enhanced_object = Subclass() enhanced_object.doSomething() //> Hello from AClass //> Hello from Subclass |
ООП: Протоколы
Протоколы объявляются так же как и классы.
1 2 3 | protocol MyFirstProtocol { // I do nothing } |
Протоколы описывают методы, свойства и другие требования, которые необходимы для определенной задачи. Например, протокол UITableViewDelegate перечисляет все методы, которые могут использоваться, чтобы реагировать на пользовательские события и сконфигурировать табличное представление.
Если класс не будет соответствовать протоколу, компилятор выдаст ошибку. Класс можно заставить соответствовать одному протоколу или множеству.
1 2 3 | class AnotherSwiftClass: MyFirstProtocol, AnotherProtocol { ... } |
Если класс наследуется от другого класса, убедитесь, что суперкласс поставлен перед списком протоколов.
1 2 3 | class AnotherSwiftClass: AClass, MyFirstProtocol, AnotherProtocol { ... } |
Примечание: протоколы используют тот же синтаксис как и обычные методы, но не позволены определить значения по умолчанию для параметров метода.
ООП: Паттерн Delegate
Один из наиболее чрезмерно используемых шаблонов проектирования при разработке для iOS является Делегат. Класс может делегировать часть своих обязанностей экземпляру другого класса. Этот паттерн реализовывается через определение протокола, который инкапсулирует делегированные обязанности. Протокол гарантирует, что новый класс обеспечит делегированный ему функционал.
Вот пример, класс Player делегирует стреляющую логику оружию:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | protocol Targetable { var life: Int { get set } func takeDamage(damage: Int) } protocol Shootable { func shoot(target: Targetable) } class Pistol: Shootable { func shoot(target: Targetable) { target.takeDamage(1) } } class Shotgun: Shootable { func shoot(target: Targetable) { target.takeDamage(5) } } class Enemy: Targetable { var life: Int = 10 func takeDamage(damage: Int) { life -= damage print("enemy lost \(damage) hit points") if life <= 0 { print("enemy is dead now") } } } class Player { var weapon: Shootable! init(weapon: Shootable) { self.weapon = weapon } func shoot(target: Targetable) { weapon.shoot(target) } } var terminator = Player(weapon: Pistol()) var enemy = Enemy() terminator.shoot(enemy) //> enemy lost 1 hit points terminator.shoot(enemy) //> enemy lost 1 hit points terminator.shoot(enemy) //> enemy lost 1 hit points terminator.shoot(enemy) //> enemy lost 1 hit points terminator.shoot(enemy) //> enemy lost 1 hit points // changing weapon because the pistol is inefficient terminator.weapon = Shotgun() terminator.shoot(enemy) //> enemy lost 5 hit points //> enemy is dead now |
ООП: Полиморфизм
Полиморфизм означает “наличие многократных форм”. Объекты различных классов могут использоваться взаимозаменяемо, если у них есть общий суперкласс.
Вот простой пример, в котором многократные экземпляры могут использоваться в качестве GraphicObject.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | class GraphicObject { func draw() { print("does nothing") } } class SpaceShip: GraphicObject { } class EmpireSpaceShip: SpaceShip { override func draw() { print("draws an empire space ship") } } class RebellionSpaceShip: SpaceShip { override func draw() { print("draws a rebellion space ship") } } class DeathStar: GraphicObject { override func draw() { print("draws the Death Star") } } var spaceShips = [EmpireSpaceShip(), RebellionSpaceShip(), DeathStar()] for spaceShip in spaceShips { spaceShip.draw() } |
Эта программа выведет в лог:
1 2 3 | draws an empire space ship draws a rebellion space ship draws the Death Star |
ООП: Паттерн Singleton
Иногда важно иметь только один экземпляр для класса. Например, в системе должен быть только один менеджер окон (или только одна файловая система или один менеджер движения на iPhone). Чтобы достигнуть этого эффекта в Swift, мы собираемся представить экземпляр-одиночку, используя свойство класса.
1 2 3 4 5 6 7 8 9 10 11 | class Singleton { struct Static { static let instance = Singleton() } class var sharedInstance: Singleton { return Static.instance } } Singleton.sharedInstance |
или
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | import Foundation class DispatchSingleton { struct Static { static var onceToken : dispatch_once_t = 0 static var instance : DispatchSingleton? = nil } class var sharedInstance : DispatchSingleton { dispatch_once(&Static.onceToken) { Static.instance = DispatchSingleton() } return Static.instance! } } DispatchSingleton.sharedInstance |
ООП: Model View Controller
Лучшее объяснение, которое я нашел, было от Apple:
Шаблон проектирования Model-View-Controller (MVC) присваивает объектам в приложении одну из трех ролей: модель, представление или контроллер. Паттерн определяет не только ролевую игру этих объектов, а и способ их связи между собой. Каждый из трех типов объектов отделен от других абстрактными границами и связывается с объектами других типов через эти границы. Набор объектов определенного типа MVC в приложении иногда упоминается как уровни — например, уровень модели.
MVC — ключевая часть хорошего проектирования на Cocoa. Преимущества этого паттерна многочисленные. Много объектов в приложениях могут допускать повторное использование, и их интерфейсы могут быть лучше определенными. Приложения, использующие MVC, также более легко расширяемы, чем другие приложения. Кроме того, много технологий и архитектур Cocoa основываются на MVC и требуют, чтобы ваши пользовательские объекты играли одну из ролей MVC.
Объекты Model инкапсулируют данные, определенные для приложения, и определяют логику и вычисления, которые управляют и обрабатывают те данные. Например, объект model мог бы представлять символ в игре или контакт в адресной книге. Объект model может иметь отношения «к-одному» или «ко-многим» с другими объектами model. Большая часть данных, которая является частью постоянного состояния приложения должна находиться в объектах model после того, как данные загружены в приложение. Поскольку объекты model представляют знания и опыт, связанные с определенной проблемной областью, они могут быть снова использованы в подобных областях. В идеале, у объекта model не должно быть явного соединения с объектами представления (View), которые представляют его данные и позволяют пользователям редактировать их— это не должно касаться проблем представления и пользовательского интерфейса.
Пользовательские действия на уровне View, которые создают или изменяют данные, переданы через объект Controller и как результат: создают или изменяют объекты Model. Когда объект Model изменяется (например, новые данные получены по сетевому соединению), это уведомляет объект Controller, который обновляет соответствующие объекты View.
Объект View — объект в приложении, который видят пользователи. Объект View может ответить на пользовательские действия. Главная цель объектов представления состоит в том, чтобы вывести на экран данные от model объектов приложения. Несмотря на это, объекты View обычно отделяются от Model объектов в приложении MVC.
Объекты View узнают об изменениях в данных Model через объекты Controller приложения и передают инициируемые пользователями изменения — например, текст, введенный в текстовом поле — через Controller, для объектов Model приложения.
Объект Controller выступает в качестве посредника между одним или более объектов View приложения и одним или более его объектов Model. Объекты Controller — мост, через который объекты View узнают об изменениях в объектах model и наоборот. Объекты Controller могут также выполнить задачи установки и координирования для приложения и управлять жизненными циклами других объектов.
Объект Controller интерпретирует пользовательские действия и передает новые или измененные данные к Model уровню. Когда Model изменился, объект Controller передает эти новые данные модели к объектам View для того что бы они могли вывести их на экран.
ООП: Полезные материалы для углубления в тему
And it can be paraphrased?
——
Больничный лист купить нижний