summaryrefslogtreecommitdiffhomepage
path: root/ru-ru/objective-c-ru.html.markdown
diff options
context:
space:
mode:
Diffstat (limited to 'ru-ru/objective-c-ru.html.markdown')
-rw-r--r--ru-ru/objective-c-ru.html.markdown656
1 files changed, 579 insertions, 77 deletions
diff --git a/ru-ru/objective-c-ru.html.markdown b/ru-ru/objective-c-ru.html.markdown
index 3246de82..8eac4ddb 100644
--- a/ru-ru/objective-c-ru.html.markdown
+++ b/ru-ru/objective-c-ru.html.markdown
@@ -1,106 +1,171 @@
---
language: Objective-C
-filename: LearnObjectiveC.m
+filename: LearnObjectiveC-ru.m
contributors:
- ["Eugene Yagrushkin", "www.about.me/yagrushkin"]
- ["Yannick Loriot", "https://github.com/YannickL"]
+ - ["Levi Bostian", "https://github.com/levibostian"]
translators:
- ["Evlogy Sutormin", "http://evlogii.com"]
+ - ["Dmitry Bessonov", "https://github.com/TheDmitry"]
lang: ru-ru
---
-Objective-C — компилируемый объектно-ориентированный язык программирования, используемый корпорацией Apple,
-построенный на основе языка Си и парадигм Smalltalk.
-В частности, объектная модель построена в стиле Smalltalk — то есть объектам посылаются сообщения.
+Objective-C — основной язык программирования, используемый корпорацией Apple
+для операционных систем OS X и iOS и их соответствующих фреймворках Cocoa и
+Cocoa Touch.
+Он является объектно-ориентированным языком программирования общего назначения,
+который добавляет обмен сообщениями в Smalltalk-стиле к языку программирования C.
-```objective_c
-// Однострочный комментарий
+```objective-c
+// Однострочные комментарии начинаются с //
/*
-Многострочный
-комментарий
+Так выглядят многострочные комментарии
*/
-// Импорт файлов фреймворка Foundation с помощью #import
+// Импорт заголовочных файлов фреймворка Foundation с помощью #import
+// Используйте <>, чтобы импортировать глобальные файлы (обычно фреймворки)
+// Используйте "", чтобы импортировать локальные файлы (из проекта)
#import <Foundation/Foundation.h>
#import "MyClass.h"
-// Точка входа в программу это функция main,
-// которая возвращает целый тип integer
+// Если вы включили модули для iOS >= 7.0 или OS X >= 10.9 проектов в
+// Xcode 5, вы можете импортировать фреймворки подобным образом:
+@import Foundation;
+
+// Точка входа в программу - это функция main,
+// которая возвращает целый тип
int main (int argc, const char * argv[])
{
- // Создание autorelease pool для управления памятью
+ // Создание autorelease pool для управления памятью в программе
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
-
+ // В место этого воспользуйтесь @autoreleasepool, если вы используете
+ // автоматический подсчет ссылок (ARC)
+ @autoreleasepool {
+
// Используйте NSLog для печати в консоль
- NSLog(@"Hello World!"); // Напечатает строку "Hello World!"
+ NSLog(@"Привет Мир!"); // Напечатает строку "Привет Мир!"
///////////////////////////////////////
// Типы и переменные
///////////////////////////////////////
- // Простое объявление
+ // Объявление простых типов
int myPrimitive1 = 1;
long myPrimitive2 = 234554664565;
+ // Объявление объектов
// Помещайте * в начало названия объекта для строго типизированного объявления
MyClass *myObject1 = nil; // Строгая типизация
id myObject2 = nil; // Слабая типизация
-
- NSLog(@"%@ and %@", myObject1, [myObject2 description]); // напечатает "(null) and (null)"
// %@ – это объект
- // 'description' это общий для всех объектов метод вывода данных
+ // 'description' - это общий для всех объектов метод вывода данных
+ NSLog(@"%@ and %@", myObject1, [myObject2 description]); // напечатает "(null) and (null)"
// Строка
- NSString *worldString = @"World";
- NSLog(@"Hello %@!", worldString); // напечатает "Hello World!"
+ NSString *worldString = @"Мир";
+ NSLog(@"Привет %@!", worldString); // напечатает "Привет Мир!"
+ // NSMutableString - это изменяемая версия NSString-объекта
+ NSMutableString *mutableString = [NSMutableString stringWithString:@"Привет"];
+ [mutableString appendString:@" Мир!"];
+ NSLog(@"%@", mutableString); // напечатает => "Привет Мир!"
// Символьные литералы
NSNumber *theLetterZNumber = @'Z';
- char theLetterZ = [theLetterZNumber charValue];
+ char theLetterZ = [theLetterZNumber charValue]; // или 'Z'
NSLog(@"%c", theLetterZ);
- // Целочисленный литералы
+ // Целочисленные литералы
NSNumber *fortyTwoNumber = @42;
- int fortyTwo = [fortyTwoNumber intValue];
+ int fortyTwo = [fortyTwoNumber intValue]; // или '42'
NSLog(@"%i", fortyTwo);
// Беззнаковый целочисленный литерал
NSNumber *fortyTwoUnsignedNumber = @42U;
- unsigned int fortyTwoUnsigned = [fortyTwoUnsignedNumber unsignedIntValue];
+ unsigned int fortyTwoUnsigned = [fortyTwoUnsignedNumber unsignedIntValue]; // или 42
NSLog(@"%u", fortyTwoUnsigned);
NSNumber *fortyTwoShortNumber = [NSNumber numberWithShort:42];
- short fortyTwoShort = [fortyTwoShortNumber shortValue];
+ short fortyTwoShort = [fortyTwoShortNumber shortValue]; // или 42
NSLog(@"%hi", fortyTwoShort);
+ NSNumber *fortyOneShortNumber = [NSNumber numberWithShort:41];
+ unsigned short fortyOneUnsigned = [fortyOneShortNumber unsignedShortValue]; // или 41
+ NSLog(@"%u", fortyOneUnsigned);
+
NSNumber *fortyTwoLongNumber = @42L;
- long fortyTwoLong = [fortyTwoLongNumber longValue];
+ long fortyTwoLong = [fortyTwoLongNumber longValue]; // или 42
NSLog(@"%li", fortyTwoLong);
+
+ NSNumber *fiftyThreeLongNumber = @53L;
+ unsigned long fiftyThreeUnsigned = [fiftyThreeLongNumber unsignedLongValue]; // или 53
+ NSLog(@"%lu", fiftyThreeUnsigned);
// Вещественный литерал
NSNumber *piFloatNumber = @3.141592654F;
- float piFloat = [piFloatNumber floatValue];
- NSLog(@"%f", piFloat);
+ float piFloat = [piFloatNumber floatValue]; // или 3.141592654f
+ NSLog(@"%f", piFloat); // напечатает 3.141592654
+ NSLog(@"%5.2f", piFloat); // напечатает " 3.14"
NSNumber *piDoubleNumber = @3.1415926535;
- double piDouble = [piDoubleNumber doubleValue];
+ double piDouble = [piDoubleNumber doubleValue]; // или 3.1415926535
NSLog(@"%f", piDouble);
-
+ NSLog(@"%4.2f", piDouble); // напечатает "3.14"
+
+ // NSDecimalNumber - это класс с фиксированной точкой, который является
+ // более точным, чем float или double
+ NSDecimalNumber *oneDecNum = [NSDecimalNumber decimalNumberWithString:@"10.99"];
+ NSDecimalNumber *twoDecNum = [NSDecimalNumber decimalNumberWithString:@"5.002"];
+ // NSDecimalNumber не способен использовать стандартные +, -, *, / операторы,
+ // поэтому он предоставляет свои собственные:
+ [oneDecNum decimalNumberByAdding:twoDecNum];
+ [oneDecNum decimalNumberBySubtracting:twoDecNum];
+ [oneDecNum decimalNumberByMultiplyingBy:twoDecNum];
+ [oneDecNum decimalNumberByDividingBy:twoDecNum];
+ NSLog(@"%@", oneDecNum); // напечатает "10.99", т.к. NSDecimalNumber - изменяемый
+
// BOOL (булевый) литерал
NSNumber *yesNumber = @YES;
NSNumber *noNumber = @NO;
-
+ // или
+ BOOL yesBool = YES;
+ BOOL noBool = NO;
+ NSLog(@"%i", yesBool); // напечатает 1
+
// Массив
+ // Может содержать различные типы данных, но должен быть объектом Objective-C
NSArray *anArray = @[@1, @2, @3, @4];
NSNumber *thirdNumber = anArray[2];
- NSLog(@"Third number = %@", thirdNumber); // Print "Third number = 3"
+ NSLog(@"Третье число = %@", thirdNumber); // Напечатает "Третье число = 3"
+ // NSMutableArray - это изменяемая версия NSArray, допускающая вам изменять
+ // элементы в массиве и расширять или сокращать массив.
+ // Удобный, но не эффективный как NSArray.
+ NSMutableArray *mutableArray = [NSMutableArray arrayWithCapacity:2];
+ [mutableArray addObject:@"Привет"];
+ [mutableArray addObject:@"Мир"];
+ [mutableArray removeObjectAtIndex:0];
+ NSLog(@"%@", [mutableArray objectAtIndex:0]); // напечатает "Мир"
// Словарь
- NSDictionary *aDictionary = @{ @"key1" : @"value1", @"key2" : @"value2" };
- NSObject *valueObject = aDictionary[@"A Key"];
- NSLog(@"Object = %@", valueObject); // Напечатает "Object = (null)"
-
+ NSDictionary *aDictionary = @{ @"ключ1" : @"значение1", @"ключ2" : @"значение2" };
+ NSObject *valueObject = aDictionary[@"Ключ"];
+ NSLog(@"Объект = %@", valueObject); // Напечатает "Объект = (null)"
+ // NSMutableDictionary тоже доступен, как изменяемый словарь
+ NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionaryWithCapacity:2];
+ [mutableDictionary setObject:@"значение1" forKey:@"ключ1"];
+ [mutableDictionary setObject:@"значение2" forKey:@"ключ2"];
+ [mutableDictionary removeObjectForKey:@"ключ1"];
+
+ // Множество
+ NSSet *set = [NSSet setWithObjects:@"Привет", @"Привет", @"Мир", nil];
+ NSLog(@"%@", set); // напечатает {(Hello, World)} (порядок может отличаться)
+ // NSMutableSet тоже доступен, как изменяемое множество
+ NSMutableSet *mutableSet = [NSMutableSet setWithCapacity:2];
+ [mutableSet addObject:@"Привет"];
+ [mutableSet addObject:@"Привет"];
+ NSLog(@"%@", mutableSet); // напечатает => {(Привет)}
+
///////////////////////////////////////
// Операторы
///////////////////////////////////////
@@ -124,13 +189,13 @@ int main (int argc, const char * argv[])
// Условный оператор
if (NO)
{
- NSLog(@"I am never run");
+ NSLog(@"Я никогда не выполнюсь");
} else if (0)
{
- NSLog(@"I am also never run");
+ NSLog(@"Я тоже никогда не выполнюсь");
} else
{
- NSLog(@"I print");
+ NSLog(@"Я напечатаюсь");
}
// Ветвление с множественным выбором
@@ -138,15 +203,15 @@ int main (int argc, const char * argv[])
{
case 0:
{
- NSLog(@"I am never run");
+ NSLog(@"Я никогда не выполнюсь");
} break;
case 1:
{
- NSLog(@"I am also never run");
+ NSLog(@"Я тоже никогда не выполнюсь");
} break;
default:
{
- NSLog(@"I print");
+ NSLog(@"Я напечатаюсь");
} break;
}
@@ -170,7 +235,7 @@ int main (int argc, const char * argv[])
// "2,"
// "3,"
- // // Цикл просмотра
+ // Цикл просмотра
NSArray *values = @[@0, @1, @2, @3];
for (NSNumber *value in values)
{
@@ -180,20 +245,32 @@ int main (int argc, const char * argv[])
// "2,"
// "3,"
+ // Цикл for для объектов. Может использоваться с любым объектом Objective-C
+ for (id item in values) {
+ NSLog(@"%@,", item);
+ } // напечатает => "0,"
+ // "1,"
+ // "2,"
+ // "3,"
+
// Обработка исключений
@try
{
// Ваше исключение здесь
@throw [NSException exceptionWithName:@"FileNotFoundException"
- reason:@"File Not Found on System" userInfo:nil];
+ reason:@"Файл не найден в системе" userInfo:nil];
} @catch (NSException * e)
{
- NSLog(@"Exception: %@", e);
+ NSLog(@"Исключение: %@", e);
} @finally
{
- NSLog(@"Finally");
- } // => напечатает "Exception: File Not Found on System"
- // "Finally"
+ NSLog(@"В конце отводится время для очистки.");
+ } // => напечатает "Исключение: Файл не найден в системе"
+ // "В конце отводится время для очистки."
+
+ // NSError - это полезные объекты для аргументов функции, чтобы заполнить их
+ // пользовательскими ошибками.
+ NSError *error = [NSError errorWithDomain:@"Неправильный эл. адрес." code:4 userInfo:nil];
///////////////////////////////////////
// Объекты
@@ -203,13 +280,16 @@ int main (int argc, const char * argv[])
// Объект не является полнофункциональным пока обе части не выполнятся.
MyClass *myObject = [[MyClass alloc] init];
- // В Objective-C можель ООП базируется на передаче сообщений.
+ // В Objective-C модель ООП базируется на передаче сообщений.
// В Objective-C Вы не просто вызваете метод; вы посылаете сообщение.
- [myObject instanceMethodWithParameter:@"Steve Jobs"];
+ [myObject instanceMethodWithParameter:@"Стив Джобс"];
// Очищайте память, перед завершением работы программы.
[pool drain];
+ // Конец @autoreleasepool
+ }
+
// Конец программы.
return 0;
}
@@ -222,63 +302,144 @@ int main (int argc, const char * argv[])
// Синтаксис объявления:
// @interface ИмяКласса : ИмяКлассаРодителя <ИмплементируемыеПротоколы>
// {
-// Объявление переменных;
+// тип имя; <= Объявление переменных;
// }
+// @property тип имя; <= объявление свойств
// -/+ (тип) Объявление метода(ов).
// @end
-
-
-@interface MyClass : NSObject <MyProtocol>
+@interface MyClass : NSObject <MyProtocol> // NSObject - это базовый класс в Objective-C.
{
- int count;
- id data;
+ // Объявления экземпляров переменных (может существовать в файлах интерфейса или реализвации)
+ int count; // По умолчанию защищенный доступ.
+ @private id data; // Приватный доступ (Намного удобнее объявлять в файле реализации)
NSString *name;
}
-// При объявлении свойств сразу генерируются геттер и сеттер
-@property int count;
-@property (copy) NSString *name; // Скопировать объект в ходе присвоения.
-@property (readonly) id data; // Генерация только геттера
+// Удобное обозначение для переменных с открытым (public) доступом
+// автоматически генерируется сеттер-метод
+// По умолчанию название сеттер-метода начинается с 'set' с последующим именем
+// переменной из @property
+@property int propInt; // Имя сеттер-метода = 'setPropInt'
+@property (copy) id copyId; // (copy) => Скопировать объект в ходе присвоения.
+// (readonly) => Не позволяет установить значение вне @interface
+@property (readonly) NSString *roString; // Используйте @synthesize
+ // в @implementation, чтобы создать аксессор
+// Вы можете настроить геттер и сеттер имена вместо используемого 'set'-имени по умолчанию:
+@property (getter=lengthGet, setter=lengthSet:) int length;
// Методы
-+/- (return type)methodSignature:(Parameter Type *)parameterName;
++/- (возвращаемый тип)сигнатураМетода:(Параметр типа *)имяПараметра;
// + для методов класса
+ (NSString *)classMethod;
++ (MyClass *)myClassFromHeight:(NSNumber *)defaultHeight;
-// - для метода объекта
+// - для методов объекта
- (NSString *)instanceMethodWithParameter:(NSString *)string;
- (NSNumber *)methodAParameterAsString:(NSString*)string andAParameterAsNumber:(NSNumber *)number;
-@end
+// Методы-конструктор с аргументом:
+- (id)initWithDistance:(int)defaultDistance;
+// В Objective-C имена методов очень описательные. Всегда имена методов соответствуют своим аргументам
+
+@end // Устанавливает конец интерфейса (interface)
+
+
+// Чтобы обратиться к открытым (public) переменным из файла реализации, @property генерирует сеттер-метод
+// автоматически. Название метода - это 'set' с последующим именем переменной из @property:
+MyClass *myClass = [[MyClass alloc] init]; // создает экземпляр объекта класса MyClass
+[myClass setCount:10];
+NSLog(@"%d", [myClass count]); // напечатает => 10
+// Или используйте свой геттер и сеттер методы, которые определены в @interface:
+[myClass lengthSet:32];
+NSLog(@"%i", [myClass lengthGet]); // напечатает => 32
+// Для удобства вы можете использовать точечную нотацию,
+// чтобы установить и получить доступ к переменным объекта:
+myClass.count = 45;
+NSLog(@"%i", myClass.count); // напечатает => 45
+
+// Вызов методов класса:
+NSString *classMethodString = [MyClass classMethod];
+MyClass *classFromName = [MyClass myClassFromName:@"Привет"];
+
+// Вызов методов экземпляра:
+MyClass *myClass = [[MyClass alloc] init]; // Создает экземпляр объекта MyClass
+NSString *stringFromInstanceMethod = [myClass instanceMethodWithParameter:@"Привет"];
+
+// Селекторы
+// Это способ динамически представить методы. Используйте для вызова методов класса, передайте методы
+// через функции, чтобы сказать другим классам, что они должны вызвать их и сохранить методы
+// как переменные
+// SEL - это тип данных. @selector() вернет селектор из предоставленного имени метода
+// methodAParameterAsString:andAParameterAsNumber: - это название метода в MyClass
+SEL selectorVar = @selector(methodAParameterAsString:andAParameterAsNumber:);
+if ([myClass respondsToSelector:selectorVar]) { // Проверяет содержит ли класс метод
+ // Необходимо установить все аргументы метода в один объект, что отправить его в performSelector-функцию
+ NSArray *arguments = [NSArray arrayWithObjects:@"Привет", @4, nil];
+ [myClass performSelector:selectorVar withObject:arguments]; // Вызывает метод
+} else {
+ // NSStringFromSelector() вернет NSString название метода полученного селектором
+ NSLog(@"MyClass не содержит метод: %@", NSStringFromSelector(selectedVar));
+}
// Имплементируйте методы в файле МойКласс.m:
+@implementation MyClass {
+ long distance; // Переменная экземпляра с закрытым (private) доступом
+ NSNumber height;
+}
-@implementation MyClass
+// To access a public variable from the interface file, use '_' followed by variable name:
+_count = 5; // References "int count" from MyClass interface
+// Access variables defined in implementation file:
+distance = 18; // References "long distance" from MyClass implementation
+// To use @property variable in implementation, use @synthesize to create accessor variable:
+@synthesize roString = _roString; // _roString available now in @implementation
+
+// Called before calling any class methods or instantiating any objects
++ (void)initialize
+{
+ if (self == [MyClass class]) {
+ distance = 0;
+ }
+}
// Вызывается при высвобождении памяти под объектом
- (void)dealloc
{
+ [height release]; // Если не используется ARC, убедитесь в освобождении переменных объекта класса
+ [super dealloc]; // and call parent class dealloc
}
-// Конструкторы – это способ осздания объектов класса.
-// Это обычный конструктор вызываемый при создании объекта клсааа.
+// Конструкторы – это способ создания объектов класса.
+// Это конструктор по умолчанию, который вызывается, когда объект инициализируется.
- (id)init
{
- if ((self = [super init]))
+ if ((self = [super init])) // 'super' используется для того, чтобы обратиться к методам родительского класса
{
- self.count = 1;
+ self.count = 1; // 'self' используется для вызова самого себя
}
return self;
}
+// Можно создать конструкторы, которые содержат аргументы:
+- (id)initWithDistance:(int)defaultDistance
+{
+ distance = defaultDistance;
+ return self;
+}
+ (NSString *)classMethod
{
return [[self alloc] init];
}
++ (MyClass *)myClassFromHeight:(NSNumber *)defaultHeight
+{
+ height = defaultHeight;
+ return [[self alloc] init];
+}
+
- (NSString *)instanceMethodWithParameter:(NSString *)string
{
- return @"New string";
+ return @"Новая строка";
}
- (NSNumber *)methodAParameterAsString:(NSString*)string andAParameterAsNumber:(NSNumber *)number
@@ -286,23 +447,364 @@ int main (int argc, const char * argv[])
return @42;
}
+// Objective-C не содержит объявление приватных методов, но вы можете имитировать их.
+// Чтобы сымитировать приватный метод, создайте метод в @implementation, но не в @interface.
+- (NSNumber *)secretPrivateMethod {
+ return @72;
+}
+[self secretPrivateMethod]; // Вызывает приватный метод
+
// Методы объявленные в МyProtocol (см. далее)
- (void)myProtocolMethod
{
- // имплементация
+ // операторы
}
+@end // Устанавливает конец реализации (implementation)
+
+///////////////////////////////////////
+// Категории
+///////////////////////////////////////
+// Категория - это группа методов предназначенные для того, чтобы расширить класс. Они позволяют вам добавить новые методы
+// к существующему классу для организационных целей. Это не стоит путать с подклассами.
+// Подклассы предназначены для ИЗМЕНЕНИЯ функциональности объекта пока как категории ДОБАВЛЯЮТ
+// функциональность в объект.
+// Категории позволяют вам:
+// -- Добавлять методы в существующий класс для организационных целей.
+// -- Допускает вам расширять объекты Objective-C классов (напр.: NSString) добавить ваши собственные методы.
+// -- Добавляет возможность создать защищенные и закрытые методы классов.
+// ПРИМЕЧАНИЕ: Не переопределяйте методы базового класса в категории даже если у вас есть возможность это сделать
+// to. Переопределение методов может привести к ошибкам компиляции позднее между различными категориями и это
+// нарушает цель категорий, чтобы добавлять только функциональность. Вместо этого подклассы переопределяют методы.
+
+// Здесь простой базовый класс Car.
+@interface Car : NSObject
+
+@property NSString *make;
+@property NSString *color;
+
+- (void)turnOn;
+- (void)accelerate;
+
@end
-/*
- * Протокол объявляет методы которые должны быть имплементированы
- * Протокол не является классом. Он просто определяет интерфейс,
- * который должен быть имплементирован.
- */
+// И реализация базового класса Car:
+#import "Car.h"
+
+@implementation Car
+
+@synthesize make = _make;
+@synthesize color = _color;
+
+- (void)turnOn {
+ NSLog(@"Машина заведена.");
+}
+- (void)accelerate {
+ NSLog(@"Ускорение.");
+}
-@protocol MyProtocol
- - (void)myProtocolMethod;
@end
+
+// Теперь, если мы хотели создать грузовой объект, мы должны вместо создания подкласса класса Car, как это будет
+// изменять функциональность Car чтобы вести себя подобно грузовику. Но давайте посмотрим, если мы хотим только добавить
+// функциональность в существующий Car. Хороший пример должен быть чистить автомобиль. Итак мы создадим
+// категорию для добавления его очистительных методов:
+// @interface ИмяФайла: Car+Clean.h (ИмяБазовогоКласса+ИмяКатегории.h)
+#import "Car.h" // Убедитесь в том, что базовый класс импортирован для расширения.
+
+@interface Car (Clean) // Имя категории внутри (), следующие после имени базового класса.
+
+- (void)washWindows; // Названия новых методов, которые мы добавляем в наш объект Car.
+- (void)wax;
+
+@end
+
+// @implementation имя файла: Car+Clean.m (ИмяБазовогоКласса+ИмяКатегории.m)
+#import "Car+Clean.h" // Импортируйте Очистку файл @interface категории.
+
+@implementation Car (Clean)
+
+- (void)washWindows {
+ NSLog(@"Окна промыли.");
+}
+- (void)wax {
+ NSLog(@"Воском натерли.");
+}
+
+@end
+
+// Любой экземпляр объекта Car имеет возможность воспользоваться категорией. Все, что нужно сделать, это импортировать ее:
+#import "Car+Clean.h" // Импортировать как множество различных категорий, как вы хотите использовать.
+#import "Car.h" // Кроме того, необходимо импортировать базовый класс для использования его оригинальные функциональные возможности.
+
+int main (int argc, const char * argv[]) {
+ @autoreleasepool {
+ Car *mustang = [[Car alloc] init];
+ mustang.color = @"Красный";
+ mustang.make = @"Форд";
+
+ [mustang turnOn]; // Используйте методы из базового класса Car.
+ [mustang washWindows]; // Используйте методы категории Clean из класса Car.
+ }
+ return 0;
+}
+
+// Objective-C не поддерживает объявление защищенных методов, но вы можете имитировать их.
+// Создайте категорию, содержащую все защищенные методы, затем импортируйте ее только в
+// @implementation-файле класса, относящегося к классу Car:
+@interface Car (Protected) // Наименование категории с помощью 'Protected'
+// дает знать, что методы защищенные.
+
+- (void)lockCar; // Здесь перечисляются методы, которые должны быть созданы
+// только с помощью объектов класса Car.
+
+@end
+// Чтобы воспользоваться защищенными методами, импортируйте категорию, затем реализуйте методы:
+#import "Car+Protected.h" // Запомните, делайте импорт только в файле с @implementation.
+
+@implementation Car
+
+- (void)lockCar {
+ NSLog(@"Машина закрыта."); // Экземпляры класса Car не могут использовать
+// метод lockCar, потому что он объявлен не в @interface.
+}
+
+@end
+
+///////////////////////////////////////
+// Расширения
+///////////////////////////////////////
+// Расширения позволяют вам переопределять атрибуты свойств и методов
+// с открытым доступом в @interface.
+// @interface имя файла: Shape.h
+@interface Shape : NSObject // Расширение базового класса Shape переопределяет
+ // свои поля ниже.
+
+@property (readonly) NSNumber *numOfSides;
+
+- (int)getNumOfSides;
+
+@end
+// Вы можете переопределить numOfSides-переменную или getNumOfSides-метод
+// Внесение изменений с помощью расширения делается следующим образом:
+// @implementation имя файла: Shape.m
+#import "Shape.h"
+// Расширения "живут" в том же файле, где и @implementation класса.
+@interface Shape () // После имени базового класса скобки () объявляют расширение.
+
+@property (copy) NSNumber *numOfSides; // Делает numOfSides-свойство
+ // копирующим (copy) вместо свойства только для чтения (readonly).
+-(NSNumber)getNumOfSides; // Изменяет метод getNumOfSides так,
+ // чтобы он возвращал объект NSNumber вместо типа int.
+-(void)privateMethod; // Вы также можете создать новый закрытый метод
+ // внутри расширения.
+
+@end
+// Главный @implementation:
+@implementation Shape
+
+@synthesize numOfSides = _numOfSides;
+
+-(NSNumber)getNumOfSides { // Все операторы внутри расширения
+ // должны быть в @implementation.
+ return _numOfSides;
+}
+-(void)privateMethod {
+ NSLog(@"Закрытый метод созданный с помощью расширения.");
+ NSLog(@"Экземпляр Shape не может вызвать этот метод.");
+}
+
+@end
+
+///////////////////////////////////////
+// Протоколы
+///////////////////////////////////////
+// Протокол объявляет методы, которые могут быть реализованы с помощью
+// любого класса. Протоколы сами по себе не являются классами. Они просто
+// определяют интерфейс, который должен быть реализован другими объектами.
+// @protocol имя файла: "CarUtilities.h"
+@protocol CarUtilities <NSObject> // <NSObject> => Имя другого протокола,
+// который включен в этот протокол.
+ @property BOOL engineOn; // Адаптирующий класс должен определить
+// все @synthesize для @property и
+ - (void)turnOnEngine; // определить все методы.
+@end
+// Ниже пример класса, реализующий протокол.
+#import "CarUtilities.h" // Импорт файла с @protocol.
+
+@interface Car : NSObject <CarUtilities> // Внутри <> имя протокола
+// Здесь вам не нужно указывать @property или имена методов для CarUtilities.
+// Они нужны только для @implementation.
+- (void)turnOnEngineWithUtilities:(id <CarUtilities>)car; // Вы также можете
+// указать тип протоколов.
+@end
+// В @implementation нужно реализовать все @property и методы для протокола.
+@implementation Car : NSObject <CarUtilities>
+
+@synthesize engineOn = _engineOn; // Создайте @synthesize-оператор
+// для "@property engineOn".
+
+- (void)turnOnEngine { // Реализуйте turnOnEngine как вам угодно. Протоколы
+// не определят,
+ _engineOn = YES; // как вам реализовать метод, он только требует,
+// чтобы вы реализовали его.
+}
+// Вы можете использовать протокол как данные, если вы знаете, что он реализует
+// методы и переменные.
+- (void)turnOnEngineWithCarUtilities:(id <CarUtilities>)objectOfSomeKind {
+ [objectOfSomeKind engineOn]; // У вас есть доступ к переменным объекта
+ [objectOfSomeKind turnOnEngine]; // и методам.
+ [objectOfSomeKind engineOn]; // Может или не может быть значение YES. Класс
+// реализует как нужно.
+}
+
+@end
+// Экземпляры класса Car сейчас имеют доступ к протоколу.
+Car *carInstance = [[Car alloc] init];
+[carInstance setEngineOn:NO];
+[carInstance turnOnEngine];
+if ([carInstance engineOn]) {
+ NSLog(@"Двигатель запущен."); // напечатает => "Двигатель запущен."
+}
+// Убедитись в том, что объект типа 'id' реализует протокол перед вызовом методов протокола:
+if ([myClass conformsToProtocol:@protocol(CarUtilities)]) {
+ NSLog(@"Не работает, т.к. класс MyClass не реализует протокол CarUtilities.");
+} else if ([carInstance conformsToProtocol:@protocol(CarUtilities)]) {
+ NSLog(@"Работает как класс Car, который реализует протокол CarUtilities.");
+}
+// Категории тоже могут реализовать протоколы:
+// @interface Car (CarCategory) <CarUtilities>
+// Вы можете реализовать много протоколов:
+// @interface Car : NSObject <CarUtilities, CarCleaning>
+// ЗАМЕЧАНИЕ: Если два или более протоколов полагаются друг на друга,
+// убедитесь, что они ранее объявлены:
+#import "Brother.h"
+
+@protocol Brother; // Оператор раннего объявления. Без него компилятор
+// выдаст ошибку.
+
+@protocol Sister <NSObject>
+
+- (void)beNiceToBrother:(id <Brother>)brother;
+
+@end
+
+// Рассмотрите проблему, где протокол Sister полагается на протокол Brother,
+// а Brother полагается на Sister.
+#import "Sister.h"
+
+@protocol Sister; // Эти строки предотвращают рекурсию, решая этим проблему.
+
+@protocol Brother <NSObject>
+
+- (void)beNiceToSister:(id <Sister>)sister;
+
+@end
+
+
+///////////////////////////////////////
+// Блоки
+///////////////////////////////////////
+// Блоки - это операторы кода, наподобие функции, которую возможно использовать
+// как данные.
+// Ниже простой блок с целочисленным аргументом, и возвращает аргумент плюс 4.
+int (^addUp)(int n); // Объявите переменную, чтобы сохранить блок.
+void (^noParameterBlockVar)(void); // Пример объявления блока-переменной
+// без аргументов.
+// Блоки имею доступ к переменным в той же области видимости. Но переменные
+// будут только для чтения, и значения переданных в блок станут значением
+// переменной, когда блок создастся.
+int outsideVar = 17; // Если мы редактируем outsideVar после объявления addUp,
+// outsideVar остается равным 17.
+__block long mutableVar = 3; // __block делают переменные перезаписываемыми
+// в блоках, в отличие от outsideVar.
+addUp = ^(int n) { // Удалите (int n) в блоке, чтобы не принимать
+// какие-либо параметры.
+ NSLog(@"Вы можете иметь столько строк в блоке, сколько вы хотели.");
+ NSSet *blockSet; // Также вы можете объявить локальные переменные.
+ mutableVar = 32; // Присвоить новое значение к __block-переменной.
+ return n + outsideVar; // Необязательный оператор возврата.
+}
+int addUp = add(10 + 16); // Вызывает блок кода с аргументами.
+// Блоки часто используются как аргументы функции, чтобы позже их вызвать, или
+// как функции обратного вызова (callbacks).
+@implementation BlockExample : NSObject
+
+- (void)runBlock:(void (^)(NSString))block {
+ NSLog(@"В аргументе блок ничего не возвращает и принимает NSString-объект.");
+ block(@"Аргумент передан блоку на исполнение."); // Вызов блока.
+}
+
+@end
+
+
+///////////////////////////////////////
+// Управление памятью
+///////////////////////////////////////
+/*
+Для каждого объекта, используемого в приложении, должна быть выделена память
+для таких объектов. Когда приложение прекращает использование объекта, память
+должна быть освобождена, чтобы гарантировать эффективность приложения.
+Objective-C не использует сборщик мусора, а вместо этого применяет подсчет ссылок.
+Пока существует по крайней мере одна ссылка на объект (также называется
+"владение" объектом), то объект будет доступен к использованию (еще известно
+как "право владения").
+
+Когда экземпляр владеет объектом, его ссылка увеличивается на один. Когда
+объекта освобождается, счетчик ссылки уменьшается на один. Когда счетчик ссылки
+равен нулю, объект удаляется из памяти.
+
+Над всеми объектами взаимодействуют, следуя паттерну:
+(1) создание объекта, (2) использование объекта, (3) затем освобождение объекта из памяти.
+*/
+
+MyClass *classVar = [MyClass alloc]; // 'alloc' устанавливает счетчик ссылки
+// объекта classVar на 1 и возвращает указатель на объект.
+[classVar release]; // Уменьшает счетчик ссылки объекта classVar
+// 'retain' заявляет право собственности на существующий экземпляр объекта
+// и увеличивает счетчик ссылки. Затем вернет указатель на объект.
+MyClass *newVar = [classVar retain]; // Если classVar освободится, объект
+// останется в памяти, потому что newVar - владелец
+[classVar autorelease]; // Удалит право на владение объектом
+// в конце @autoreleasepool блока. Вернет указатель на объект.
+
+// @property может использовать 'retain' и 'assign' тоже для маленького
+// удобного определения
+@property (retain) MyClass *instance; // Освободит старое значение и сохранит
+// одно новое (строгая ссылка)
+@property (assign) NSSet *set; // Укажет на новое значение
+// без сохранения/освобождения старого значения (слабая ссылка)
+
+// Автоматический подсчет ссылок (ARC)
+// Управление памятью может быть трудным, поэтому в Xcode 4.2 и iOS 4 введен
+// автоматический подсчет ссылок (ARC).
+// ARC - это особенность компилятора, который помещает "retain", "release"
+// и "autorelease" автоматически за вас тогда, когда используется ARC,
+// вам не нужно больше обращаться к "retain", "relase" или "autorelease"
+MyClass *arcMyClass = [[MyClass alloc] init];
+// ... код, использующий объект arcMyClass
+// Без ARC, вам нужно было бы вызвать: [arcMyClass release] после того, как вы
+// завершите работу с объектом arcMyClass. Но с ARC,
+// теперь этого не нужно делать. Он будет помещать release-вызов за вас
+
+// Что касается 'assign' и 'retain' @property атрибутов, в ARC вы должны
+// использовать 'weak' и 'strong'
+@property (weak) MyClass *weakVar; // 'weak' не принимает право на владение
+// объектом. Если исходный счетчик ссылки экземпляра обнуляется,
+// weakVar-свойство автоматически примет значение nil,
+// во избежание падения приложения
+@property (strong) MyClass *strongVar; // 'strong' принимает право на владение
+// объектом. Гарантирует, что объект останится в памяти для использования
+
+// Для обычных переменных (не объявленных с помощью @property), используйте
+// следующий способ:
+__strong NSString *strongString; // По умолчанию. Переменная сохраняется в памяти,
+// пока она не покинет область видимости
+__weak NSSet *weakSet; // Слабая ссылка на существующий объект. Когда существующий
+// объект освобождается, weakSet принимает nil
+__unsafe_unretained NSArray *unsafeArray; // Похож на __weak, но unsafeArray
+// не принимает nil, когда существующий объект освобождается
+
```
## На почитать