summaryrefslogtreecommitdiffhomepage
path: root/ru-ru/objective-c-ru.html.markdown
blob: a1c6e45bdb2df028c3062f677f0daf60635649d7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
---
language: Objective-C
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
для операционных систем macOS и iOS и их соответствующих фреймворках Cocoa и
Cocoa Touch.
Он является объектно-ориентированным языком программирования общего назначения,
который добавляет обмен сообщениями в Smalltalk-стиле к языку программирования C.

```objective-c
// Однострочные комментарии начинаются с //

/*
Так выглядят многострочные комментарии
*/

// Импорт заголовочных файлов фреймворка Foundation с помощью #import
// Используйте <>, чтобы импортировать глобальные файлы (обычно фреймворки)
// Используйте "", чтобы импортировать локальные файлы (из проекта)
#import <Foundation/Foundation.h>
#import "MyClass.h"

// Если вы включили модули для iOS >= 7.0 или OS X >= 10.9 проектов в
// Xcode 5, вы можете импортировать фреймворки подобным образом:
@import Foundation;

// Точка входа в программу - это функция main,
// которая возвращает целый тип
int main (int argc, const char * argv[])
{
    // Создание autorelease pool для управления памятью в программе
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    // В место этого воспользуйтесь @autoreleasepool, если вы используете
    // автоматический подсчет ссылок (ARC)
    @autoreleasepool {
    
    // Используйте NSLog для печати в консоль
    NSLog(@"Привет Мир!"); // Напечатает строку "Привет Мир!"
 
    ///////////////////////////////////////
    // Типы и переменные
    ///////////////////////////////////////
    
    // Объявление простых типов
    int myPrimitive1  = 1;
    long myPrimitive2 = 234554664565;
    
    // Объявление объектов
    // Помещайте * в начало названия объекта для строго типизированного объявления
    MyClass *myObject1 = nil;  // Строгая типизация	
    id       myObject2 = nil;  // Слабая типизация 
    // %@ – это объект
    // 'description' - это общий для всех объектов метод вывода данных
    NSLog(@"%@ and %@", myObject1, [myObject2 description]); // напечатает "(null) and (null)"
    
    // Строка
    NSString *worldString = @"Мир";
    NSLog(@"Привет %@!", worldString); // напечатает "Привет Мир!"
    // NSMutableString - это изменяемая версия NSString-объекта
    NSMutableString *mutableString = [NSMutableString stringWithString:@"Привет"];
    [mutableString appendString:@" Мир!"];
    NSLog(@"%@", mutableString); // напечатает => "Привет Мир!"
    
    // Символьные литералы
    NSNumber *theLetterZNumber = @'Z';
    char theLetterZ            = [theLetterZNumber charValue]; // или 'Z'
    NSLog(@"%c", theLetterZ);

    // Целочисленные литералы
    NSNumber *fortyTwoNumber = @42;
    int fortyTwo             = [fortyTwoNumber intValue]; // или '42'
    NSLog(@"%i", fortyTwo);
    
    // Беззнаковый целочисленный литерал
    NSNumber *fortyTwoUnsignedNumber = @42U;
    unsigned int fortyTwoUnsigned    = [fortyTwoUnsignedNumber unsignedIntValue]; // или 42
    NSLog(@"%u", fortyTwoUnsigned);

    NSNumber *fortyTwoShortNumber = [NSNumber numberWithShort:42];
    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]; // или 42
    NSLog(@"%li", fortyTwoLong);
    
    NSNumber *fiftyThreeLongNumber   = @53L;
    unsigned long fiftyThreeUnsigned = [fiftyThreeLongNumber unsignedLongValue]; // или 53
    NSLog(@"%lu", fiftyThreeUnsigned);

    // Вещественный литерал
    NSNumber *piFloatNumber = @3.141592654F;
    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]; // или 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(@"Третье число = %@", thirdNumber); // Напечатает "Третье число = 3"
    // NSMutableArray - это изменяемая версия NSArray, допускающая вам изменять
    // элементы в массиве и расширять или сокращать массив.
    // Удобный, но не эффективный как NSArray.
    NSMutableArray *mutableArray = [NSMutableArray arrayWithCapacity:2];
    [mutableArray addObject:@"Привет"];
    [mutableArray addObject:@"Мир"];
    [mutableArray removeObjectAtIndex:0];
    NSLog(@"%@", [mutableArray objectAtIndex:0]); // напечатает "Мир"

    // Словарь
    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); // напечатает => {(Привет)}
    
    ///////////////////////////////////////
    // Операторы
    ///////////////////////////////////////
    
    // Операторы работают также как в Си.
    // Например:
    2 + 5; // => 7
    4.2f + 5.1f; // => 9.3f
    3 == 2; // => 0 (НЕТ)
    3 != 2; // => 1 (ДА)
    1 && 1; // => 1 (логическое И)
    0 || 1; // => 1 (логическое ИЛИ)
    ~0x0F; // => 0xF0 (побитовое отрицание)
    0x0F & 0xF0; // => 0x00 (побитовое И)
    0x01 << 1; // => 0x02 (побитовый сдвиг влево (на 1))

    ///////////////////////////////////////
    // Структуры ветвления
    ///////////////////////////////////////

    // Условный оператор
    if (NO)
    {
        NSLog(@"Я никогда не выполнюсь");
    } else if (0)
    {
        NSLog(@"Я тоже никогда не выполнюсь");
    } else
    {
        NSLog(@"Я напечатаюсь");
    }

    // Ветвление с множественным выбором
    switch (2)
    {
        case 0:
        {
            NSLog(@"Я никогда не выполнюсь");
        } break;
        case 1:
        {
            NSLog(@"Я тоже никогда не выполнюсь");
        } break;
        default:
        {
            NSLog(@"Я напечатаюсь");
        } break;
    }
    
    // Цикл с предусловием
    int ii = 0;
    while (ii < 4)
    {
        NSLog(@"%d,", ii++); // ii++ инкрементирует ii после передачи значения
    } // => напечатает "0," 
      //               "1,"
      //               "2,"
      //               "3,"

    // Цикл со счётчиком
    int jj;
    for (jj=0; jj < 4; jj++)
    {
        NSLog(@"%d,", jj);
    } // => напечатает "0," 
      //               "1,"
      //               "2,"
      //               "3,"
     
    // Цикл просмотра           
    NSArray *values = @[@0, @1, @2, @3];
    for (NSNumber *value in values)
    {
        NSLog(@"%@,", value);
    } // => напечатает "0," 
      //               "1,"
      //               "2,"
      //               "3,"

    // Цикл for для объектов. Может использоваться с любым объектом Objective-C
    for (id item in values) { 
        NSLog(@"%@,", item); 
    } // напечатает => "0," 
      //           "1,"
      //           "2,"
      //           "3,"      
      
    // Обработка исключений
    @try
    {
        // Ваше исключение здесь
        @throw [NSException exceptionWithName:@"FileNotFoundException"
                            reason:@"Файл не найден в системе" userInfo:nil];
    } @catch (NSException * e)
    {
        NSLog(@"Исключение: %@", e);
    } @finally
    {
        NSLog(@"В конце отводится время для очистки.");
    } // => напечатает "Исключение: Файл не найден в системе"
      //               "В конце отводится время для очистки."
 
    // NSError - это полезные объекты для аргументов функции, чтобы заполнить их
    // пользовательскими ошибками.
    NSError *error = [NSError errorWithDomain:@"Неправильный эл. адрес." code:4 userInfo:nil];
 
    ///////////////////////////////////////
    // Объекты
    ///////////////////////////////////////
    
    // Создание объектов через выделение памяти и инициализацию.
    // Объект не является полнофункциональным пока обе части не выполнятся.
    MyClass *myObject = [[MyClass alloc] init];
        
    // В Objective-C модель ООП базируется на передаче сообщений.
    // В Objective-C Вы не просто вызваете метод; вы посылаете сообщение.
    [myObject instanceMethodWithParameter:@"Стив Джобс"];

    // Очищайте память, перед завершением работы программы.
    [pool drain];
    
    // Конец @autoreleasepool
    }
    
    // Конец программы.
    return 0;
}

///////////////////////////////////////
// Классы и функции
///////////////////////////////////////

// Объявляйте свой класс в файле МойКласс.h
// Синтаксис объявления:
// @interface ИмяКласса : ИмяКлассаРодителя <ИмплементируемыеПротоколы>
// {
//    тип имя; <= Объявление переменных;
// }
// @property тип имя; <= объявление свойств
// -/+ (тип) Объявление метода(ов).
// @end
@interface MyClass : NSObject <MyProtocol> // NSObject - это базовый класс в Objective-C.
{
    // Объявления экземпляров переменных (может существовать в файлах интерфейса или реализвации)
    int count; // По умолчанию защищенный доступ.
    @private id data; // Приватный доступ (Намного удобнее объявлять в файле реализации)
    NSString *name;
}
// Удобное обозначение для переменных с открытым (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;

// Методы
+/- (возвращаемый тип)сигнатураМетода:(Параметр типа *)имяПараметра;

// + для методов класса
+ (NSString *)classMethod;
+ (MyClass *)myClassFromHeight:(NSNumber *)defaultHeight;

// - для методов объекта
- (NSString *)instanceMethodWithParameter:(NSString *)string;
- (NSNumber *)methodAParameterAsString:(NSString*)string andAParameterAsNumber:(NSNumber *)number;

// Методы-конструктор с аргументом:
- (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));
}

// Имплементируйте методы в файле MyClass.m:
@implementation MyClass {
    long distance; // Переменная экземпляра с закрытым (private) доступом
    NSNumber height;
}

// Для доступа к public переменной, объявленной в интерфейсе, используйте '_' перед названием переменной:
_count = 5; // Ссылается на "int count" из интерфейса MyClass
// Получение доступа к переменной, объявленной в реализации происходит следующим образом:
distance = 18; // Ссылается на "long distance" из реализации MyClass
// Для использования в иплементации переменной, объявленной в интерфейсе с помощью @property,
// следует использовать @synthesize для создания переменной аксессора:
@synthesize roString = _roString; // Теперь _roString доступна в @implementation (реализации интерфейса)

// Вызывается в первую очередь, перед вызовом других медотов класса или инициализации других объектов
+ (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])) // 'super' используется для того, чтобы обратиться к методам родительского класса
    {
        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 @"Новая строка";
}

- (NSNumber *)methodAParameterAsString:(NSString*)string andAParameterAsNumber:(NSNumber *)number
{
    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(@"Ускорение.");
}

@end

// Теперь, если мы хотим создать объект Truck - грузовик, мы должны создать подкласс класса Car, что
// изменит функциональность 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", "release" или "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, когда существующий объект освобождается
```

## На почитать

[Wikipedia Objective-C](http://en.wikipedia.org/wiki/Objective-C)

[Learning Objective-C](http://developer.apple.com/library/ios/referencelibrary/GettingStarted/Learning_Objective-C_A_Primer/)

[iOS For High School Students: Getting Started](http://www.raywenderlich.com/5600/ios-for-high-school-students-getting-started)

[iOS разработчик: Обзор книг для новичка](http://habrahabr.ru/post/166213/)

[Хочешь быть iOS разработчиком? Будь им!](http://www.pvsm.ru/ios/12662/print/)