diff options
| -rw-r--r-- | ru-ru/objective-c-ru.html.markdown | 654 | 
1 files changed, 578 insertions, 76 deletions
| diff --git a/ru-ru/objective-c-ru.html.markdown b/ru-ru/objective-c-ru.html.markdown index 3246de82..ddff2e5c 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 -// Однострочный комментарий +// Однострочные комментарии начинаются с //  /* -Многострочный -комментарий +Так выглядят многострочные комментарии  */ -// Импорт файлов фреймворка 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, когда существующий объект освобождается +  ```  ## На почитать | 
