Статьи

Изучение основы Фонда

Основа 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 и бесплатными мостами.

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


Изучение нового навыка лучше всего сделать на практике, поэтому создайте новый проект в XCode и выберите шаблон проекта инструмента командной строки, как мы делали ранее в этой серии. Шаблон инструмента командной строки можно найти в категории приложений в разделе OS X. Нажмите Далее, чтобы продолжить.

Назовите новый проект Foundation и введите название организации и идентификатор компании. Для этого проекта важно установить тип проекта Foundation . Сообщите Xcode, где вы хотите сохранить проект, и нажмите « Создать» .

Наша площадка для остальной части этой статьи будет main.m и окно консоли Xcode. Откройте main.m , выбрав его в Project Navigator на левой боковой панели и убедитесь, что окно консоли видно, нажав среднюю кнопку элемента управления View на панели инструментов Xcode.

Нажмите кнопку « Выполнить» в левом верхнем углу, чтобы построить и запустить текущую схему. Если все прошло хорошо, вы должны увидеть Hello, World! появиться в окне консоли внизу.


Фреймворк Foundation — это нечто большее, чем набор классов для работы с числами, строками и коллекциями (массивами, словарями и наборами). Он также определяет десятки протоколов, функций, типов данных и констант.

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

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

Действительно необходимо импортировать файл заголовка класса, прежде чем вы сможете его использовать. Вы делаете это, добавляя оператор импорта, как мы видели ранее в этой серии. Тем не менее, основы Фонда предоставляет удобный способ облегчить этот процесс. Единственный файл, который вам нужно импортировать — это Foundation.h, как показано в следующем фрагменте кода.

1
#import <Foundation/Foundation.h>;

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

Когда вы создаете новый проект в Xcode и устанавливаете тип проекта в Foundation , Xcode будет:

  • связать проект с рамками Фонда
  • добавьте вышеупомянутое утверждение импорта к main.m
  • добавьте приведенный выше оператор импорта в предварительно скомпилированный заголовочный файл проекта (* .pch)

Откройте main.m, чтобы проверить это, и раскройте папку frameworks в Навигаторе проектов , щелкнув по маленькому треугольнику слева от него. Я вернусь к предварительно скомпилированному заголовочному файлу и его назначению, когда мы посмотрим на структуру UIKit.

Несколько языков, таких как Perl, Python и C ++, обеспечивают поддержку множественного наследования , что означает, что класс может наследоваться — быть подклассом — более чем одного класса.

Хотя Objective-C не обеспечивает поддержку множественного наследования, он поддерживает множественное наследование посредством спецификации в форме протоколов. Что это значит? Вместо того, чтобы наследовать от класса, протокол определяет список методов, которые классы реализуют, если они соответствуют протоколу.

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

Преимущества протоколов многообразны. Когда класс принимает или соответствует протоколу, ожидается, что класс реализует (обязательные) методы, объявленные в протоколе.

Протоколы Objective-C очень похожи на интерфейсы в Java. Это означает, что протокол может использоваться для объявления интерфейса к объекту без раскрытия класса объекта.

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

В дополнение к корневому классу NSObject платформа Foundation также определяет протокол NSObject . Объекты, соответствующие протоколу NSObject , можно спросить об их классе и суперклассе, можно сравнить с другими объектами и ответить на self как мы видели в статье об Objective-C. Это лишь небольшая часть поведения, добавляемого к объектам, соответствующим протоколу NSObject .

Объекты, соответствующие протоколу NSCoding , могут быть закодированы и декодированы. Это необходимо для объектов, которые необходимо архивировать или распространять. Архивирование объектов происходит, например, когда объект или граф объектов хранятся на диске.

Протокол NSCopying объявляет только один метод, copyWithZone: Если класс должен поддерживать копирование объектов, он должен соответствовать протоколу NSCopying . Копирование объекта осуществляется путем отправки ему сообщения copy или copyWithZone:


Класс NSObject является корневым классом подавляющего большинства иерархий классов Objective-C. Помните ли вы, что мы создали экземпляр класса Book ранее в этой серии? Мы отправили классу Book сообщение о выделении и отправили полученному объекту сообщение init . Оба метода объявлены в классе NSObject .

Унаследовавшись от корневого класса NSObject , объекты знают, как вести себя как объекты Objective C и как взаимодействовать со средой выполнения Objective C. Не должно быть сюрпризом, что NSObject соответствует протоколу NSObject , который мы видели ранее.

Удалите оператор NSLog main.m и вставьте на его место следующий фрагмент кода.

1
2
3
4
NSObject *myFirstObject = [[NSObject alloc] init];
NSLog(@»Class > %@», [myFirstObject class]);
NSLog(@»Superclass > %@», [myFirstObject superclass]);
NSLog(@»Conforms to Protocol > %i», [myFirstObject conformsToProtocol:@protocol(NSObject)]);

Мы начинаем с создания экземпляра NSObject и сохраняем ссылку на него в переменной myFirstObject . Во второй строке мы записываем имя класса нового объекта в консоль. Метод class возвращает экземпляр NSString , строковый объект, поэтому мы используем спецификатор формата %@ в выражении NSLog .

Затем мы запрашиваем myFirstObject для его суперкласса и заканчиваем проверкой того, что myFirstObject соответствует протоколу myFirstObject . Вас смущает @protocol(NSObject) ? Это не более чем ссылка на протокол NSObject .

Нажмите Run и проверьте вывод в окне консоли. Вы удивлены результатом? Поскольку NSObject является корневым классом, он не имеет суперкласса.


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

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

Позвольте мне проиллюстрировать это на примере. Добавьте следующий фрагмент кода в main.m.

1
2
3
4
NSNumber *myNumber = [NSNumber numberWithDouble:854736e+13];
NSLog(@»Double Value > %f», [myNumber doubleValue]);
NSLog(@»Float Value > %f», [myNumber floatValue]);
NSLog(@»Int Value > %i», [myNumber intValue]);

Мы начнем с создания нового экземпляра NSNumber , передав double значение в numberWithDouble: Затем мы извлекаем сохраненное значение, используя три разных метода NSNumber . Результаты не отражают значение, сохраненное в myNumber по очевидным причинам.

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


Экземпляры класса NSString управляют массивом символов unichar образующих строку текста. Тонкое, но важное отличие обычной строки C, которая управляет символами char , заключается в том, что символ unichar является многобайтовым символом.

Как следует из его названия, символ unichar идеально подходит для обработки символов Unicode. Благодаря этой реализации класс NSString обеспечивает NSString поддержку интернационализации.

Я хочу подчеркнуть, что строка, управляемая экземпляром NSString является неизменной. Это означает, что после создания строки ее нельзя изменить. Разработчики из других языков, таких как PHP, Ruby или JavaScript, могут быть смущены этим поведением.

Платформа Foundation также определяет изменяемый подкласс NSString , NSMutableString , который можно изменить после его создания.

Существуют различные способы создания строковых объектов. Самый простой способ создать строковый объект — вызвать string метод в классе NSString , который возвращает пустой строковый объект. Посмотрите на ссылку на класс NSString для полного списка инициализаторов.

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

1
NSString *string1 = @»This is a string literal.»;

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

Давайте исследуем NSString и его изменяемый подкласс NSMutableString , добавив следующий фрагмент в main.m.

1
2
3
4
5
NSString *string1 = @»This is a string literal.»;
NSString *string2 = [[NSString alloc] initWithFormat:@»Strings can be created many ways.»];
NSMutableString *mutableString = [[NSMutableString alloc] initWithString:string1];
[mutableString appendFormat:@» %@», string2];
NSLog(@»%@», mutableString);

Мы начинаем с создания строкового объекта с использованием строкового литерала. Во второй строке мы создаем вторую строку с помощью одного из специализированных инициализаторов, которые предоставляет NSString . Изменяемая строка затем создается путем передачи первой строки в качестве аргумента. Чтобы проиллюстрировать, что изменяемые строки могут быть изменены после создания, string2 добавляется к изменяемой строке и регистрируется в окне консоли.


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

Важно понимать, что экземпляры NSArray , NSSet и NSDictionary могут хранить только объекты. Это означает, что невозможно хранить скалярные типы, указатели или структуры ни в одном из этих классов коллекций — или их подклассах — компилятор выдаст ошибку, если вы это сделаете. Решение состоит в том, чтобы обернуть скалярные типы, указатели и структуры в экземпляр NSValue или NSNumber как мы видели ранее в этой статье.

Добавьте следующий фрагмент кода в main.m для изучения NSArray и его изменяемого аналога NSMutableArray .

1
2
3
4
5
6
7
NSArray *myArray = [NSArray arrayWithObjects:@»Bread», @»Butter», @»Milk», @»Eggs», nil];
NSLog(@»Number of Elements > %li», [myArray count]);
NSLog(@»Object at Index 2 > %@», [myArray objectAtIndex:2]);
 
NSMutableArray *myMutableArray = [NSMutableArray arrayWithObject:[NSNumber numberWithInt:265]];
[myMutableArray addObject:[NSNumber numberWithInt:45]];
NSLog(@»Mutable Array > %@», myMutableArray);

В первой строке мы создаем массив с помощью arrayWithObjects: class. Этот метод принимает переменное число аргументов — объектов — с последним аргументом, nil которые не включены в массив. Во второй и третьей строке мы запрашиваем у массива количество объектов в массиве и объект, сохраненный с индексом 2 соответственно.

Поскольку NSMutableArray наследуется от NSArray , он ведет себя во многом так же, как NSArray . Основное отличие состоит в том, что объекты можно добавлять и удалять из массива после его создания.

Прежде чем двигаться дальше, я хочу сказать несколько слов о NSSet . Этот класс похож на NSArray , но основные отличия заключаются в том, что коллекция объектов, которыми управляет набор, неупорядочена и дублирование не допускается.

Преимущество NSSet том, что запросы к его объектам выполняются быстрее, если вам нужно только знать, содержится ли объект в наборе. Основа также определяет NSOrderedSet . Экземпляры этого класса имеют преимущества NSSet , но также отслеживают положение каждого объекта.


Как и массивы, словари являются общей концепцией в большинстве языков программирования. Например, в Ruby они называются хешами. Основная концепция проста: словарь управляет статической коллекцией пар ключ-значение или записей.

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

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

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

Как и NSArray , платформа Foundation определяет изменяемый подкласс NSDictionary , NSMutableDictionary . Существуют различные способы создания словаря. Взгляните на следующий фрагмент кода.

1
2
3
4
NSString *keyA = @»myKey»;
NSString *keyB = @»myKey»;
NSDictionary *myDictionary = [NSDictionary dictionaryWithObject:@»This is a string literal» forKey:keyA];
NSLog(@»%@», [myDictionary objectForKey:keyB]);

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

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

Важно обратить внимание на детали. Хотя мы использовали keyA в качестве ключа пары ключ-значение и keyB в качестве ключа для извлечения значения или объекта пары ключ-значение, словарь дал нам правильный объект. Класс NSDictionary достаточно умен, чтобы знать, что мы хотим, чтобы объект был связан со строкой myKey . Что это значит? Даже если объекты keyA и keyB являются разными объектами, строка, которую они содержат, одинакова, и это именно то, что класс NSDictionary использует для ссылки на объект.

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

1
2
3
NSMutableDictionary *myMutableDictionary = [NSMutableDictionary dictionary];
[myMutableDictionary setObject:myDictionary forKey:@»myDictionary»];
NSLog(@»%@», myMutableDictionary);

Ранее в этой статье я познакомил вас со строковыми литералами Objective-C, такими как @"This is a string literal." , Они принимают форму строкового литерала C с префиксом @ . Как вы, наверное, уже знаете, знак @ указывает, что мы входим в территорию Objective-C.

Литерал Objective-C — это не более чем блок кода, который ссылается на объект Objective-C. С выпуском Xcode 4.5 теперь вы также можете использовать литералы Objective C для NSNumber , NSArray и NSDictionary . Посмотрите на следующий фрагмент кода, чтобы увидеть, как это работает.

01
02
03
04
05
06
07
08
09
10
11
NSNumber *oldNumber1 = [NSNumber numberWithBool:YES];
NSNumber *newNubmer1 = @YES;
 
NSNumber *oldNumber2 = [NSNumber numberWithInt:2147];
NSNumber *newNubmer2 = @2147;
 
NSArray *oldArray = [NSArray arrayWithObjects:@»one», @»two», @»three», nil];
NSArray *newArray = @[@»one», @»two», @»three»];
 
NSDictionary *oldDictionary = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:12345] forKey:@»key»];
NSDictionary *newDictionary = @{@»key»: @12345};

Литералы Objective-C не только крутые и сексуальные, они также делают ваш код более читабельным. Марк Хэммондс написал учебник по литералам Objective-C . Прочтите сообщение Марка для более полного обзора литералов Objective-C.


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

1
NSLog(@»%@ — %i — %f», @»an object», 3, 3.14);

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


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

Тем не менее, не обязательно знать детали каждого класса или функции, определенных в платформе Foundation, чтобы начать разработку под iOS. Вы узнаете больше о платформе Foundation, изучая iOS SDK.

В следующей статье мы рассмотрим фреймворк UIKit, а также обсудим все тонкости приложения iOS.