Основа Framework — это хлеб с маслом в наборе инструментов разработчика iOS. Он предоставляет корневой класс NSObject
и большое количество фундаментальных строительных блоков для разработки под iOS, от классов для чисел и строк до массивов и словарей. Вначале платформа Foundation может показаться немного скучной, но она использует много энергии и является незаменимой для разработки приложений для iOS.
Слово о базовом фонде
В предыдущей статье я кратко упомянул Core Foundation и его связь с Foundation. Несмотря на то, что мы не будем явно использовать платформу Core Foundation в оставшейся части этой серии, полезно ознакомиться с этой платформой и узнать, чем она отличается от ее объектно-ориентированного элемента, Foundation, который вы будете широко использовать.
В то время как платформа Foundation реализована в Objective-C, платформа Core Foundation основана на языке C. Несмотря на это различие, платформа Core Foundation реализует ограниченную объектную модель. Эта объектная модель позволяет определять набор непрозрачных типов, которые часто называют объектами, несмотря на то, что они, строго говоря, не являются объектами.
Основная цель обеих платформ схожа, позволяя обмениваться данными и кодом между различными библиотеками и платформами. Базовый фонд также включает поддержку интернационализации. Ключевой компонент этой поддержки предоставляется через непрозрачный тип CFString
, который эффективно управляет массивом символов Unicode .
Как я уже упоминал ранее, мост по бесплатному соединению буквально сокращает разрыв между обеими платформами, позволяя заменять объекты Какао на Базовые объекты Основы в параметрах функций и наоборот.
Важно отметить, что автоматический подсчет ссылок (ARC) не управляет «объектами» Core Foundation. Это означает, что вы несете ответственность за управление памятью при работе с Core Foundation. Майк Эш написал отличную статью об автоматическом подсчете ссылок и о том, как использовать ARC с Core Foundation и бесплатными мостами.
Посетите справочник по базовой платформе Apple Core Foundation, если вы хотите узнать больше о платформе и получить полный список непрозрачных типов платформы.
Практика, Практика, Практика
Изучение нового навыка лучше всего делать на практике. Давайте начнем с создания новой игровой площадки в Xcode. Назовите игровую площадку Foundation и установите Platform на iOS . Нажмите Далее, чтобы продолжить. Сообщите Xcode, где вы хотите сохранить игровую площадку, и нажмите « Создать» .
Вот как должно выглядеть содержимое детской площадки.
1
2
3
4
5
|
//: Playground — noun: a place where people can play
import UIKit
var str = «Hello, playground»
|
Детская площадка содержит комментарий вверху, оператор импорта для инфраструктуры UIKit и объявление переменной. Справа вы можете увидеть выход игровой площадки.
Поскольку мы будем работать с платформой Foundation, нам нужно заменить оператор импорта для UIKit на оператор импорта для Foundation. Удалите комментарий вверху, обновите оператор импорта и удалите объявление переменной.
1
|
import Foundation
|
Фонд
Фреймворк Foundation — это нечто большее, чем набор классов для работы с числами, строками и коллекциями (массивами, словарями и наборами). Он также определяет десятки протоколов, функций, типов данных и констант.
В оставшейся части этой статьи я сосредоточусь прежде всего на классах, которые вы будете использовать чаще всего при разработке приложений для iOS. Однако я также кратко расскажу о трех ключевых протоколах, определенных платформой Foundation, NSCoding
, NSCopying
и NSCopying
.
протоколы
Несколько языков, таких как Perl, Python и C ++, обеспечивают поддержку множественного наследования . Это означает, что класс может происходить из подкласса более чем одного класса.
Хотя Swift и Objective-C не предоставляют поддержку множественного наследования, они поддерживают множественное наследование посредством спецификации в форме протоколов. Мы уже рассматривали протоколы ранее в этой серии, но есть важная деталь, которую мы еще не обсуждали.
Необязательные и обязательные методы
Помните, что требуется каждый метод протокола Swift. Если тип, соответствующий протоколу Swift, не реализует все свойства и методы, определенные протоколом, компилятор выдаст ошибку. Это не относится к протоколам Objective-C. В Objective-C методы протокола могут быть помечены как необязательные. Если метод протокола является необязательным, тип, соответствующий протоколу, не требуется для реализации метода.
Поскольку подавляющее большинство платформ iOS SDK написано на Objective-C, мы встретимся с рядом протоколов Objective-C, которые определяют дополнительные методы. Важно помнить, что требуется каждое свойство и метод протокола Swift.
Преимущества
Преимущества протоколов многообразны. Когда класс принимает или соответствует протоколу, ожидается, что класс реализует методы, объявленные протоколом. Для некоторых из вас протоколы могут напоминать интерфейсы в Java. Это означает, что протокол может использоваться для объявления интерфейса с объектом без раскрытия типа объекта.
Многократное наследование имеет свои преимущества, но, безусловно, имеет свои недостатки . Преимущество протоколов заключается в том, что несвязанные типы, перечисления, классы и структуры могут по-прежнему иметь сходное поведение при использовании протоколов.
NSObject
В дополнение к корневому классу NSObject
платформа Foundation также определяет протокол NSObject
. Однако в Swift классы и протоколы не могут иметь одинаковые имена. В результате протокол NSObject
известен как NSObjectProtocol
в Swift.
Объекты, соответствующие протоколу NSObjectProtocol
, могут спрашивать об их классе и суперклассе, могут сравниваться с другими объектами и отвечать на self
. Это лишь небольшая часть поведения, добавляемого к объектам, соответствующим протоколу NSObjectProtocol
.
NSCoding
Объекты, соответствующие протоколу NSCoding
, могут быть закодированы и декодированы. Это необходимо для объектов, которые необходимо архивировать или распространять. Архивирование объекта, например, происходит, когда объект или граф объекта сохраняются на диске.
NSCopying
Протокол NSCopying
объявляет только один метод, copyWithZone(_:)
. Если класс должен поддерживать копирование объектов, он должен соответствовать протоколу NSCopying
. Копирование объекта осуществляется путем отправки ему сообщения copy()
или copyWithZone(_:)
.
Классы
NSObject
Класс NSObject
является корневым классом подавляющего большинства иерархий классов Objective-C. Почему это важно, если мы заинтересованы в Swift? Помните, что большинство платформ iOS SDK работают на Objective-C. Даже если вы решите разработать приложение на Swift, вы все равно будете использовать Objective-C под капотом.
Унаследовавшись от корневого класса NSObject
, объекты знают, как вести себя как объекты Objective C и как взаимодействовать со средой выполнения Objective C. Не должно быть сюрпризом, что NSObject
соответствует протоколу NSObject/NSObjectProtocol
, который мы обсуждали несколько минут назад.
Давайте посмотрим, что мы получим бесплатно, если класс наследуется от класса NSObject
. Добавьте следующий фрагмент кода на свою игровую площадку. Это должно выглядеть знакомо, если вы читали предыдущие статьи этой серии. Мы объявляем класс Book
, который наследуется от NSObject
. Класс Book
реализует два метода экземпляра, chapters()
и pages()
.
1
2
3
4
5
6
7
8
9
|
class Book: NSObject {
func chapters() {
}
func pages() {
}
}
|
Поскольку Book
наследуется от NSObject
а NSObject
соответствует протоколу NSObjectProtocol
, мы можем спросить класс Book
о его поведении и дереве наследования. Посмотрите на следующий пример.
Сначала мы спрашиваем класс Book
о себе, вызывая classForCoder()
для класса Book
. Метод classForCoder()
является методом класса, что означает, что мы можем вызвать этот метод для самого класса Book
. Затем мы спрашиваем класс Book
о его суперклассе или родительском классе, классе, от которого он напрямую наследует. Это возвращает необязательный, так как не каждый класс имеет родительский класс. Неудивительно, что суперклассом Book
является NSObject
.
Следующая строка говорит нам, что Book
соответствует протоколу NSObjectProtocol
, что не является неожиданностью, поскольку оно наследует эту черту от класса NSObject
. Мы также узнаем, что Book
не соответствует протоколу NSCoding
.
Похоже, что класс Book
не отвечает на метод chapters()
. Это не так уж странно, поскольку chapters()
является методом экземпляра, а не методом класса. Это подтверждается последними двумя строками нашего примера, в которых мы создаем экземпляр экземпляра Book
и задаем ему тот же вопрос.
В приведенном выше примере мы используем метод respondsToSelector(_:)
, но вам может быть интересно, что такое селектор? Что значит «отвечать на селектор»? Селектор — это причудливое слово для имени функции или метода. Селектор используется средой выполнения Objective C для отправки сообщений объектам. Короче говоря, если вы читаете слово селектор, то подумайте о функции или методе. Более тонкие детали выходят за рамки этого урока.
NSNumber
Класс NSNumber
— это служебный класс, который управляет любым из базовых числовых типов данных. Это подкласс класса NSValue
, который предоставляет объектно-ориентированную оболочку для скалярных типов, указателей, структур и идентификаторов объектов. Класс NSNumber
определяет методы для извлечения значения, которое он хранит, для сравнения значений, а также для возврата строкового представления сохраненного значения.
Помните, что значение, полученное из экземпляра NSNumber
должно соответствовать значению, которое в нем хранится. Класс NSNumber
попытается динамически преобразовать сохраненное значение в запрошенный тип, но само собой разумеется, что существуют ограничения, присущие типам данных, NSNumber
может управлять NSNumber
.
Позвольте мне проиллюстрировать это на примере. Добавьте следующий фрагмент кода на свою игровую площадку.
Мы создаем новый экземпляр NSNumber
, передав значение Double
в init(double:)
. Затем мы запрашиваем хранимое значение, используя три разных метода NSNumber
. Как видите, результаты не всегда отражают значение, хранящееся в myNumber
.
Урок прост, будьте последовательны при использовании NSNumber
, отслеживая тип, который хранится в экземпляре NSNumber
.
NSString
Экземпляры класса NSString
управляют массивом символов unichar
образующих строку текста. Тонкое, но важное отличие обычной строки C, которая управляет символами char
, заключается в том, что символ unichar
является многобайтовым символом. Это похоже на String
тип Swift.
Как следует из его названия, символ unichar
идеально подходит для обработки символов Unicode. Благодаря этой реализации класс NSString
обеспечивает NSString
поддержку интернационализации.
Я хочу подчеркнуть, что строка, управляемая экземпляром NSString
является неизменной. Это означает, что после создания строки ее нельзя изменить. Разработчики из других языков, таких как PHP, Ruby или JavaScript, могут быть смущены этим поведением.
Платформа Foundation также определяет изменяемый подкласс NSString
, NSMutableString
, который можно изменить после инициализации.
Существуют различные способы создания строковых объектов. Самый простой способ создать строковый объект — вызвать метод string()
в классе NSString
. Это возвращает пустой строковый объект. Посмотрите на ссылку на класс NSString
для полного списка инициализаторов.
Другой распространенный путь для создания строковых объектов — через строковые литералы. В следующем примере строковый литерал присваивается stringA
Во время компиляции компилятор заменит строковый литерал экземпляром NSString
.
Обратите внимание, что мы не полагаемся на вывод типа Swift для определения типа stringA
. Второй пример, stringB
, показывает, почему это так. Если мы явно не указываем тип stringA
как NSString
, Swift думает, что мы хотим создать экземпляр String
. В примере также показано, что NSString
наследует от NSObject
а String
— нет. Помните, что тип String
в Swift — это структура, а структуры не поддерживают наследование.
Класс NSString
имеет широкий диапазон методов экземпляров и классов для создания и манипулирования строками, и вы редко, если вообще когда-либо, будете чувствовать необходимость подкласса NSString
.
Давайте исследуем NSString
и его изменяемый подкласс NSMutableString
, добавив следующий фрагмент к вашей игровой площадке.
1
2
3
4
5
|
let stringA: NSString = «This is «
let stringB: NSString = NSString(string: «a mutable string.»)
var mutableString = NSMutableString(string: stringA)
mutableString.appendString(stringB as String)
|
Мы начнем с создания двух экземпляров NSString
, один из которых использует буквальный синтаксис, а другой — init(string:)
. Изменяемая строка затем создается путем передачи первой строки в качестве аргумента. Чтобы проиллюстрировать, что изменяемые строки могут быть изменены после создания, stringB
добавляется к изменяемой строке и печатается ее значение.
NSArray
и NSSet
Класс NSArray
управляет неизменным упорядоченным списком объектов. Платформа Foundation также определяет изменяемый подкласс NSArray
, NSMutableArray
. Класс NSArray
ведет себя очень похоже на массив C или Swift с той разницей, что экземпляр NSArray
управляет объектами. Класс NSArray
объявляет широкий спектр методов, облегчающих работу с массивами, таких как методы поиска и сортировки объектов в массиве.
Важно понимать, что экземпляры NSArray
, NSSet
и NSDictionary
могут хранить только объекты. Это означает, что невозможно хранить скалярные типы, указатели или структуры ни в одном из этих классов коллекций — или их подклассах — компилятор выдаст ошибку, если вы это сделаете. Решение состоит в том, чтобы обернуть скалярные типы, указатели и структуры в экземпляр NSValue
или NSNumber
как мы видели ранее в этой статье.
Добавьте следующий фрагмент кода на игровую площадку, чтобы изучить NSArray
и его изменяемый аналог NSMutableArray
.
1
2
3
4
5
6
|
let myArray = NSArray(objects: «Bread», «Butter», «Milk», «Eggs»)
print(myArray.count)
print(myArray.objectAtIndex(2))
var myMutableArray = NSMutableArray(object: NSNumber(int: 265))
myMutableArray.addObject(NSNumber(int: 45))
|
Мы создаем массив с помощью init(objects:)
. Этот метод принимает переменное количество аргументов. Далее мы печатаем количество объектов в массиве и запрашиваем у массива объект с индексом 2
.
Поскольку NSMutableArray
наследуется от NSArray
, он ведет себя во многом так же, как NSArray
. Основное отличие состоит в том, что объекты могут быть добавлены и удалены из массива после инициализации.
Прежде чем двигаться дальше, я хочу сказать несколько слов о NSSet
. Этот класс похож на NSArray
, но основные отличия заключаются в том, что коллекция объектов, которыми управляет набор, неупорядочена и что набор не может содержать дубликаты.
Преимущество NSSet
том, что запросы к его объектам выполняются быстрее, если вам нужно только знать, содержится ли объект в наборе. Основа также определяет NSOrderedSet
. Экземпляры этого класса имеют преимущества NSSet
, но также отслеживают положение каждого объекта.
NSDictionary
Как и массивы, словари являются общей концепцией в большинстве языков программирования. Например, в Ruby они называются хешами. Основная концепция проста: словарь управляет статической коллекцией пар ключ-значение или записей.
Как и в хэше Ruby, ключ записи не обязательно должен быть строковым объектом как таковым. Это может быть объект любого типа, который соответствует протоколу NSCopying
, если ключ уникален в словаре. В большинстве случаев, однако, рекомендуется использовать строковые объекты в качестве ключей.
Как и массивы, словари не могут хранить нулевое значение. Если вы хотите представить нулевое значение, вы можете использовать NSNull
. Класс NSNull
определяет одноэлементный объект, который используется для обозначения нулевых значений в массивах, словарях и наборах.
Паттерн синглтона является важным паттерном во многих языках программирования. Он ограничивает создание экземпляра класса одним объектом. При разработке приложений для iOS вы будете часто иметь дело с одноэлементными объектами.
Как и NSArray
, платформа Foundation определяет изменяемый подкласс NSDictionary
, NSMutableDictionary
. Существуют различные способы создания словаря. Взгляните на следующий фрагмент кода.
1
2
3
4
5
6
|
let keyA: NSString = «myKey»
let keyB: NSString = «myKey»
let myDictionary = NSDictionary(object: «This is a string literal», forKey: keyA)
print(myDictionary.objectForKey(keyB))
|
Мы объявляем два отдельных объекта NSString
содержащих одну и ту же строку. Затем мы создаем экземпляр словаря, вызывая init(object:forKey:)
. Далее мы запрашиваем в словаре объект, связанный с содержимым keyB
и печатаем его значение.
Важно обратить внимание на детали. Несмотря на то, что мы использовали keyA
в качестве ключа пары ключ-значение и keyB
в качестве ключа для извлечения значения или объекта пары ключ-значение, словарь дал нам правильный объект (как необязательный). Класс NSDictionary
достаточно умен, чтобы знать, что мы хотим, чтобы объект был связан со строкой "myKey"
. Что это значит? Даже если объекты keyA
и keyB
являются разными объектами, строка, которую они содержат, одинакова, и это именно то, что класс NSDictionary
использует для ссылки на объект.
Прежде чем закончить этот урок, я бы хотел показать вам пример вложенных словарей и массивов и пример NSMutableDictionary
. Следующий фрагмент кода показывает, что словарь может содержать другой словарь или массив, а также показывает, как работать с изменяемыми словарями.
1
2
|
let myMutableDictionary = NSMutableDictionary()
myMutableDictionary.setObject(myDictionary, forKey: «myDictionary»)
|
Вывод
Несмотря на то, что мы рассмотрели много вопросов в этой статье, мы лишь немного поцарапали поверхность того, что может предложить среда Foundation. Тем не менее, не обязательно знать детали каждого класса или функции, определенных в платформе Foundation, чтобы начать разработку под iOS. Вы узнаете больше о платформе Foundation, изучая iOS SDK.
В следующей статье мы рассмотрим UIKit-фреймворк, а также я расскажу о тонкостях iOS-приложения.
Если у вас есть какие-либо вопросы или комментарии, вы можете оставить их в комментариях ниже или обратиться ко мне в Twitter .