objective-c.md

Личный сайт Go-разработчика из Казани

Objective-C — основной язык программирования, используемый корпорацией Apple для операционных систем macOS и iOS и их соответствующих фреймворках Cocoa и Cocoa Touch. Он является объектно-ориентированным языком программирования общего назначения, который добавляет обмен сообщениями в Smalltalk-стиле к языку программирования C.

1// Однострочные комментарии начинаются с // 2 3/* 4Так выглядят многострочные комментарии 5*/ 6 7// Импорт заголовочных файлов фреймворка Foundation с помощью #import 8// Используйте <>, чтобы импортировать глобальные файлы (обычно фреймворки) 9// Используйте "", чтобы импортировать локальные файлы (из проекта) 10#import <Foundation/Foundation.h> 11#import "MyClass.h" 12 13// Если вы включили модули для iOS >= 7.0 или OS X >= 10.9 проектов в 14// Xcode 5, вы можете импортировать фреймворки подобным образом: 15@import Foundation; 16 17// Точка входа в программу - это функция main, 18// которая возвращает целый тип 19int main (int argc, const char * argv[]) 20{ 21 // Создание autorelease pool для управления памятью в программе 22 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 23 // В место этого воспользуйтесь @autoreleasepool, если вы используете 24 // автоматический подсчет ссылок (ARC) 25 @autoreleasepool { 26 27 // Используйте NSLog для печати в консоль 28 NSLog(@"Привет Мир!"); // Напечатает строку "Привет Мир!" 29 30 /////////////////////////////////////// 31 // Типы и переменные 32 /////////////////////////////////////// 33 34 // Объявление простых типов 35 int myPrimitive1 = 1; 36 long myPrimitive2 = 234554664565; 37 38 // Объявление объектов 39 // Помещайте * в начало названия объекта для строго типизированного объявления 40 MyClass *myObject1 = nil; // Строгая типизация 41 id myObject2 = nil; // Слабая типизация 42 // %@ – это объект 43 // 'description' - это общий для всех объектов метод вывода данных 44 NSLog(@"%@ and %@", myObject1, [myObject2 description]); // напечатает "(null) and (null)" 45 46 // Строка 47 NSString *worldString = @"Мир"; 48 NSLog(@"Привет %@!", worldString); // напечатает "Привет Мир!" 49 // NSMutableString - это изменяемая версия NSString-объекта 50 NSMutableString *mutableString = [NSMutableString stringWithString:@"Привет"]; 51 [mutableString appendString:@" Мир!"]; 52 NSLog(@"%@", mutableString); // напечатает => "Привет Мир!" 53 54 // Символьные литералы 55 NSNumber *theLetterZNumber = @'Z'; 56 char theLetterZ = [theLetterZNumber charValue]; // или 'Z' 57 NSLog(@"%c", theLetterZ); 58 59 // Целочисленные литералы 60 NSNumber *fortyTwoNumber = @42; 61 int fortyTwo = [fortyTwoNumber intValue]; // или '42' 62 NSLog(@"%i", fortyTwo); 63 64 // Беззнаковый целочисленный литерал 65 NSNumber *fortyTwoUnsignedNumber = @42U; 66 unsigned int fortyTwoUnsigned = [fortyTwoUnsignedNumber unsignedIntValue]; // или 42 67 NSLog(@"%u", fortyTwoUnsigned); 68 69 NSNumber *fortyTwoShortNumber = [NSNumber numberWithShort:42]; 70 short fortyTwoShort = [fortyTwoShortNumber shortValue]; // или 42 71 NSLog(@"%hi", fortyTwoShort); 72 73 NSNumber *fortyOneShortNumber = [NSNumber numberWithShort:41]; 74 unsigned short fortyOneUnsigned = [fortyOneShortNumber unsignedShortValue]; // или 41 75 NSLog(@"%u", fortyOneUnsigned); 76 77 NSNumber *fortyTwoLongNumber = @42L; 78 long fortyTwoLong = [fortyTwoLongNumber longValue]; // или 42 79 NSLog(@"%li", fortyTwoLong); 80 81 NSNumber *fiftyThreeLongNumber = @53L; 82 unsigned long fiftyThreeUnsigned = [fiftyThreeLongNumber unsignedLongValue]; // или 53 83 NSLog(@"%lu", fiftyThreeUnsigned); 84 85 // Вещественный литерал 86 NSNumber *piFloatNumber = @3.141592654F; 87 float piFloat = [piFloatNumber floatValue]; // или 3.141592654f 88 NSLog(@"%f", piFloat); // напечатает 3.141592654 89 NSLog(@"%5.2f", piFloat); // напечатает " 3.14" 90 91 NSNumber *piDoubleNumber = @3.1415926535; 92 double piDouble = [piDoubleNumber doubleValue]; // или 3.1415926535 93 NSLog(@"%f", piDouble); 94 NSLog(@"%4.2f", piDouble); // напечатает "3.14" 95 96 // NSDecimalNumber - это класс с фиксированной точкой, который является 97 // более точным, чем float или double 98 NSDecimalNumber *oneDecNum = [NSDecimalNumber decimalNumberWithString:@"10.99"]; 99 NSDecimalNumber *twoDecNum = [NSDecimalNumber decimalNumberWithString:@"5.002"]; 100 // NSDecimalNumber не способен использовать стандартные +, -, *, / операторы, 101 // поэтому он предоставляет свои собственные: 102 [oneDecNum decimalNumberByAdding:twoDecNum]; 103 [oneDecNum decimalNumberBySubtracting:twoDecNum]; 104 [oneDecNum decimalNumberByMultiplyingBy:twoDecNum]; 105 [oneDecNum decimalNumberByDividingBy:twoDecNum]; 106 NSLog(@"%@", oneDecNum); // напечатает "10.99", т.к. NSDecimalNumber - изменяемый 107 108 // BOOL (булевый) литерал 109 NSNumber *yesNumber = @YES; 110 NSNumber *noNumber = @NO; 111 // или 112 BOOL yesBool = YES; 113 BOOL noBool = NO; 114 NSLog(@"%i", yesBool); // напечатает 1 115 116 // Массив 117 // Может содержать различные типы данных, но должен быть объектом Objective-C 118 NSArray *anArray = @[@1, @2, @3, @4]; 119 NSNumber *thirdNumber = anArray[2]; 120 NSLog(@"Третье число = %@", thirdNumber); // Напечатает "Третье число = 3" 121 // NSMutableArray - это изменяемая версия NSArray, допускающая вам изменять 122 // элементы в массиве и расширять или сокращать массив. 123 // Удобный, но не эффективный как NSArray. 124 NSMutableArray *mutableArray = [NSMutableArray arrayWithCapacity:2]; 125 [mutableArray addObject:@"Привет"]; 126 [mutableArray addObject:@"Мир"]; 127 [mutableArray removeObjectAtIndex:0]; 128 NSLog(@"%@", [mutableArray objectAtIndex:0]); // напечатает "Мир" 129 130 // Словарь 131 NSDictionary *aDictionary = @{ @"ключ1" : @"значение1", @"ключ2" : @"значение2" }; 132 NSObject *valueObject = aDictionary[@"Ключ"]; 133 NSLog(@"Объект = %@", valueObject); // Напечатает "Объект = (null)" 134 // NSMutableDictionary тоже доступен, как изменяемый словарь 135 NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionaryWithCapacity:2]; 136 [mutableDictionary setObject:@"значение1" forKey:@"ключ1"]; 137 [mutableDictionary setObject:@"значение2" forKey:@"ключ2"]; 138 [mutableDictionary removeObjectForKey:@"ключ1"]; 139 140 // Множество 141 NSSet *set = [NSSet setWithObjects:@"Привет", @"Привет", @"Мир", nil]; 142 NSLog(@"%@", set); // напечатает {(Hello, World)} (порядок может отличаться) 143 // NSMutableSet тоже доступен, как изменяемое множество 144 NSMutableSet *mutableSet = [NSMutableSet setWithCapacity:2]; 145 [mutableSet addObject:@"Привет"]; 146 [mutableSet addObject:@"Привет"]; 147 NSLog(@"%@", mutableSet); // напечатает => {(Привет)} 148 149 /////////////////////////////////////// 150 // Операторы 151 /////////////////////////////////////// 152 153 // Операторы работают также как в Си. 154 // Например: 155 2 + 5; // => 7 156 4.2f + 5.1f; // => 9.3f 157 3 == 2; // => 0 (НЕТ) 158 3 != 2; // => 1 (ДА) 159 1 && 1; // => 1 (логическое И) 160 0 || 1; // => 1 (логическое ИЛИ) 161 ~0x0F; // => 0xF0 (побитовое отрицание) 162 0x0F & 0xF0; // => 0x00 (побитовое И) 163 0x01 << 1; // => 0x02 (побитовый сдвиг влево (на 1)) 164 165 /////////////////////////////////////// 166 // Структуры ветвления 167 /////////////////////////////////////// 168 169 // Условный оператор 170 if (NO) 171 { 172 NSLog(@"Я никогда не выполнюсь"); 173 } else if (0) 174 { 175 NSLog(@"Я тоже никогда не выполнюсь"); 176 } else 177 { 178 NSLog(@"Я напечатаюсь"); 179 } 180 181 // Ветвление с множественным выбором 182 switch (2) 183 { 184 case 0: 185 { 186 NSLog(@"Я никогда не выполнюсь"); 187 } break; 188 case 1: 189 { 190 NSLog(@"Я тоже никогда не выполнюсь"); 191 } break; 192 default: 193 { 194 NSLog(@"Я напечатаюсь"); 195 } break; 196 } 197 198 // Цикл с предусловием 199 int ii = 0; 200 while (ii < 4) 201 { 202 NSLog(@"%d,", ii++); // ii++ инкрементирует ii после передачи значения 203 } // => напечатает "0," 204 // "1," 205 // "2," 206 // "3," 207 208 // Цикл со счётчиком 209 int jj; 210 for (jj=0; jj < 4; jj++) 211 { 212 NSLog(@"%d,", jj); 213 } // => напечатает "0," 214 // "1," 215 // "2," 216 // "3," 217 218 // Цикл просмотра 219 NSArray *values = @[@0, @1, @2, @3]; 220 for (NSNumber *value in values) 221 { 222 NSLog(@"%@,", value); 223 } // => напечатает "0," 224 // "1," 225 // "2," 226 // "3," 227 228 // Цикл for для объектов. Может использоваться с любым объектом Objective-C 229 for (id item in values) { 230 NSLog(@"%@,", item); 231 } // напечатает => "0," 232 // "1," 233 // "2," 234 // "3," 235 236 // Обработка исключений 237 @try 238 { 239 // Ваше исключение здесь 240 @throw [NSException exceptionWithName:@"FileNotFoundException" 241 reason:@"Файл не найден в системе" userInfo:nil]; 242 } @catch (NSException * e) 243 { 244 NSLog(@"Исключение: %@", e); 245 } @finally 246 { 247 NSLog(@"В конце отводится время для очистки."); 248 } // => напечатает "Исключение: Файл не найден в системе" 249 // "В конце отводится время для очистки." 250 251 // NSError - это полезные объекты для аргументов функции, чтобы заполнить их 252 // пользовательскими ошибками. 253 NSError *error = [NSError errorWithDomain:@"Неправильный эл. адрес." code:4 userInfo:nil]; 254 255 /////////////////////////////////////// 256 // Объекты 257 /////////////////////////////////////// 258 259 // Создание объектов через выделение памяти и инициализацию. 260 // Объект не является полнофункциональным пока обе части не выполнятся. 261 MyClass *myObject = [[MyClass alloc] init]; 262 263 // В Objective-C модель ООП базируется на передаче сообщений. 264 // В Objective-C Вы не просто вызваете метод; вы посылаете сообщение. 265 [myObject instanceMethodWithParameter:@"Стив Джобс"]; 266 267 // Очищайте память, перед завершением работы программы. 268 [pool drain]; 269 270 // Конец @autoreleasepool 271 } 272 273 // Конец программы. 274 return 0; 275} 276 277/////////////////////////////////////// 278// Классы и функции 279/////////////////////////////////////// 280 281// Объявляйте свой класс в файле МойКласс.h 282// Синтаксис объявления: 283// @interface ИмяКласса : ИмяКлассаРодителя <ИмплементируемыеПротоколы> 284// { 285// тип имя; <= Объявление переменных; 286// } 287// @property тип имя; <= объявление свойств 288// -/+ (тип) Объявление метода(ов). 289// @end 290@interface MyClass : NSObject <MyProtocol> // NSObject - это базовый класс в Objective-C. 291{ 292 // Объявления экземпляров переменных (может существовать в файлах интерфейса или реализвации) 293 int count; // По умолчанию защищенный доступ. 294 @private id data; // Приватный доступ (Намного удобнее объявлять в файле реализации) 295 NSString *name; 296} 297// Удобное обозначение для переменных с открытым (public) доступом 298// автоматически генерируется сеттер-метод 299// По умолчанию название сеттер-метода начинается с 'set' с последующим именем 300// переменной из @property 301@property int propInt; // Имя сеттер-метода = 'setPropInt' 302@property (copy) id copyId; // (copy) => Скопировать объект в ходе присвоения. 303// (readonly) => Не позволяет установить значение вне @interface 304@property (readonly) NSString *roString; // Используйте @synthesize 305 // в @implementation, чтобы создать аксессор 306// Вы можете настроить геттер и сеттер имена вместо используемого 'set'-имени по умолчанию: 307@property (getter=lengthGet, setter=lengthSet:) int length; 308 309// Методы 310+/- (возвращаемый тип)сигнатураМетода:(Параметр типа *)имяПараметра; 311 312// + для методов класса 313+ (NSString *)classMethod; 314+ (MyClass *)myClassFromHeight:(NSNumber *)defaultHeight; 315 316// - для методов объекта 317- (NSString *)instanceMethodWithParameter:(NSString *)string; 318- (NSNumber *)methodAParameterAsString:(NSString*)string andAParameterAsNumber:(NSNumber *)number; 319 320// Методы-конструктор с аргументом: 321- (id)initWithDistance:(int)defaultDistance; 322// В Objective-C имена методов очень описательные. Всегда имена методов соответствуют своим аргументам 323 324@end // Устанавливает конец интерфейса (interface) 325 326 327// Чтобы обратиться к открытым (public) переменным из файла реализации, @property генерирует сеттер-метод 328// автоматически. Название метода - это 'set' с последующим именем переменной из @property: 329MyClass *myClass = [[MyClass alloc] init]; // создает экземпляр объекта класса MyClass 330[myClass setCount:10]; 331NSLog(@"%d", [myClass count]); // напечатает => 10 332// Или используйте свой геттер и сеттер методы, которые определены в @interface: 333[myClass lengthSet:32]; 334NSLog(@"%i", [myClass lengthGet]); // напечатает => 32 335// Для удобства вы можете использовать точечную нотацию, 336// чтобы установить и получить доступ к переменным объекта: 337myClass.count = 45; 338NSLog(@"%i", myClass.count); // напечатает => 45 339 340// Вызов методов класса: 341NSString *classMethodString = [MyClass classMethod]; 342MyClass *classFromName = [MyClass myClassFromName:@"Привет"]; 343 344// Вызов методов экземпляра: 345MyClass *myClass = [[MyClass alloc] init]; // Создает экземпляр объекта MyClass 346NSString *stringFromInstanceMethod = [myClass instanceMethodWithParameter:@"Привет"]; 347 348// Селекторы 349// Это способ динамически представить методы. Используйте для вызова методов класса, передайте методы 350// через функции, чтобы сказать другим классам, что они должны вызвать их и сохранить методы 351// как переменные 352// SEL - это тип данных. @selector() вернет селектор из предоставленного имени метода 353// methodAParameterAsString:andAParameterAsNumber: - это название метода в MyClass 354SEL selectorVar = @selector(methodAParameterAsString:andAParameterAsNumber:); 355if ([myClass respondsToSelector:selectorVar]) { // Проверяет содержит ли класс метод 356 // Необходимо установить все аргументы метода в один объект, что отправить его в performSelector-функцию 357 NSArray *arguments = [NSArray arrayWithObjects:@"Привет", @4, nil]; 358 [myClass performSelector:selectorVar withObject:arguments]; // Вызывает метод 359} else { 360 // NSStringFromSelector() вернет NSString название метода полученного селектором 361 NSLog(@"MyClass не содержит метод: %@", NSStringFromSelector(selectedVar)); 362} 363 364// Имплементируйте методы в файле MyClass.m: 365@implementation MyClass { 366 long distance; // Переменная экземпляра с закрытым (private) доступом 367 NSNumber height; 368} 369 370// Для доступа к public переменной, объявленной в интерфейсе, используйте '_' перед названием переменной: 371_count = 5; // Ссылается на "int count" из интерфейса MyClass 372// Получение доступа к переменной, объявленной в реализации происходит следующим образом: 373distance = 18; // Ссылается на "long distance" из реализации MyClass 374// Для использования в иплементации переменной, объявленной в интерфейсе с помощью @property, 375// следует использовать @synthesize для создания переменной аксессора: 376@synthesize roString = _roString; // Теперь _roString доступна в @implementation (реализации интерфейса) 377 378// Вызывается в первую очередь, перед вызовом других медотов класса или инициализации других объектов 379+ (void)initialize 380{ 381 if (self == [MyClass class]) { 382 distance = 0; 383 } 384} 385 386// Вызывается при высвобождении памяти под объектом 387- (void)dealloc 388{ 389 [height release]; // Если не используется ARC, убедитесь в освобождении переменных объекта класса 390 [super dealloc]; // and call parent class dealloc 391} 392 393// Конструкторы – это способ создания объектов класса. 394// Это конструктор по умолчанию, который вызывается, когда объект инициализируется. 395- (id)init 396{ 397 if ((self = [super init])) // 'super' используется для того, чтобы обратиться к методам родительского класса 398 { 399 self.count = 1; // 'self' используется для вызова самого себя 400 } 401 return self; 402} 403// Можно создать конструкторы, которые содержат аргументы: 404- (id)initWithDistance:(int)defaultDistance 405{ 406 distance = defaultDistance; 407 return self; 408} 409 410+ (NSString *)classMethod 411{ 412 return [[self alloc] init]; 413} 414 415+ (MyClass *)myClassFromHeight:(NSNumber *)defaultHeight 416{ 417 height = defaultHeight; 418 return [[self alloc] init]; 419} 420 421- (NSString *)instanceMethodWithParameter:(NSString *)string 422{ 423 return @"Новая строка"; 424} 425 426- (NSNumber *)methodAParameterAsString:(NSString*)string andAParameterAsNumber:(NSNumber *)number 427{ 428 return @42; 429} 430 431// Objective-C не содержит объявление приватных методов, но вы можете имитировать их. 432// Чтобы сымитировать приватный метод, создайте метод в @implementation, но не в @interface. 433- (NSNumber *)secretPrivateMethod { 434 return @72; 435} 436[self secretPrivateMethod]; // Вызывает приватный метод 437 438// Методы объявленные в МyProtocol (см. далее) 439- (void)myProtocolMethod 440{ 441 // операторы 442} 443 444@end // Устанавливает конец реализации (implementation) 445 446/////////////////////////////////////// 447// Категории 448/////////////////////////////////////// 449// Категория - это группа методов предназначенные для того, чтобы расширить класс. Они позволяют вам добавить новые методы 450// к существующему классу для организационных целей. Это не стоит путать с подклассами. 451// Подклассы предназначены для ИЗМЕНЕНИЯ функциональности объекта пока как категории ДОБАВЛЯЮТ 452// функциональность в объект. 453// Категории позволяют вам: 454// -- Добавлять методы в существующий класс для организационных целей. 455// -- Допускает вам расширять объекты Objective-C классов (напр.: NSString) добавить ваши собственные методы. 456// -- Добавляет возможность создать защищенные и закрытые методы классов. 457// ПРИМЕЧАНИЕ: Не переопределяйте методы базового класса в категории даже если у вас есть возможность это сделать 458// to. Переопределение методов может привести к ошибкам компиляции позднее между различными категориями и это 459// нарушает цель категорий, чтобы добавлять только функциональность. Вместо этого подклассы переопределяют методы. 460 461// Здесь простой базовый класс Car. 462@interface Car : NSObject 463 464@property NSString *make; 465@property NSString *color; 466 467- (void)turnOn; 468- (void)accelerate; 469 470@end 471 472// И реализация базового класса Car: 473#import "Car.h" 474 475@implementation Car 476 477@synthesize make = _make; 478@synthesize color = _color; 479 480- (void)turnOn { 481 NSLog(@"Машина заведена."); 482} 483- (void)accelerate { 484 NSLog(@"Ускорение."); 485} 486 487@end 488 489// Теперь, если мы хотим создать объект Truck - грузовик, мы должны создать подкласс класса Car, что 490// изменит функциональность Car и позволит вести себя подобно грузовику. Но что, если мы хотим только добавить 491// определенную функциональность в уже существующий класс Car? Например - чистка автомобиля. Мы просто создадим 492// категорию, которая добавит несколько методов для чистки автомобиля в класс Car: 493// @interface ИмяФайла: Car+Clean.h (ИмяБазовогоКласса+ИмяКатегории.h) 494#import "Car.h" // Убедитесь в том, что базовый класс импортирован для расширения. 495 496@interface Car (Clean) // Имя категории внутри (), следующие после имени базового класса. 497 498- (void)washWindows; // Названия новых методов, которые мы добавляем в наш объект Car. 499- (void)wax; 500 501@end 502 503// @implementation имя файла: Car+Clean.m (ИмяБазовогоКласса+ИмяКатегории.m) 504#import "Car+Clean.h" // Импортируйте Очистку файл @interface категории. 505 506@implementation Car (Clean) 507 508- (void)washWindows { 509 NSLog(@"Окна промыли."); 510} 511- (void)wax { 512 NSLog(@"Воском натерли."); 513} 514 515@end 516 517// Любой экземпляр объекта Car имеет возможность воспользоваться категорией. Все, что нужно сделать, это импортировать ее: 518#import "Car+Clean.h" // Импортировать как множество различных категорий, как вы хотите использовать. 519#import "Car.h" // Кроме того, необходимо импортировать базовый класс для использования его оригинальные функциональные возможности. 520 521int main (int argc, const char * argv[]) { 522 @autoreleasepool { 523 Car *mustang = [[Car alloc] init]; 524 mustang.color = @"Красный"; 525 mustang.make = @"Форд"; 526 527 [mustang turnOn]; // Используйте методы из базового класса Car. 528 [mustang washWindows]; // Используйте методы категории Clean из класса Car. 529 } 530 return 0; 531} 532 533// Objective-C не поддерживает объявление защищенных методов, но вы можете имитировать их. 534// Создайте категорию, содержащую все защищенные методы, затем импортируйте ее только в 535// @implementation-файле класса, относящегося к классу Car: 536@interface Car (Protected) // Наименование категории с помощью 'Protected' 537// дает знать, что методы защищенные. 538 539- (void)lockCar; // Здесь перечисляются методы, которые должны быть созданы 540// только с помощью объектов класса Car. 541 542@end 543// Чтобы воспользоваться защищенными методами, импортируйте категорию, затем реализуйте методы: 544#import "Car+Protected.h" // Запомните, делайте импорт только в файле с @implementation. 545 546@implementation Car 547 548- (void)lockCar { 549 NSLog(@"Машина закрыта."); // Экземпляры класса Car не могут использовать 550// метод lockCar, потому что он объявлен не в @interface. 551} 552 553@end 554 555/////////////////////////////////////// 556// Расширения 557/////////////////////////////////////// 558// Расширения позволяют вам переопределять атрибуты свойств и методов 559// с открытым доступом в @interface. 560// @interface имя файла: Shape.h 561@interface Shape : NSObject // Расширение базового класса Shape переопределяет 562 // свои поля ниже. 563 564@property (readonly) NSNumber *numOfSides; 565 566- (int)getNumOfSides; 567 568@end 569// Вы можете переопределить numOfSides-переменную или getNumOfSides-метод 570// Внесение изменений с помощью расширения делается следующим образом: 571// @implementation имя файла: Shape.m 572#import "Shape.h" 573// Расширения "живут" в том же файле, где и @implementation класса. 574@interface Shape () // После имени базового класса скобки () объявляют расширение. 575 576@property (copy) NSNumber *numOfSides; // Делает numOfSides-свойство 577 // копирующим (copy) вместо свойства только для чтения (readonly). 578-(NSNumber)getNumOfSides; // Изменяет метод getNumOfSides так, 579 // чтобы он возвращал объект NSNumber вместо типа int. 580-(void)privateMethod; // Вы также можете создать новый закрытый метод 581 // внутри расширения. 582 583@end 584// Главный @implementation: 585@implementation Shape 586 587@synthesize numOfSides = _numOfSides; 588 589-(NSNumber)getNumOfSides { // Все операторы внутри расширения 590 // должны быть в @implementation. 591 return _numOfSides; 592} 593-(void)privateMethod { 594 NSLog(@"Закрытый метод созданный с помощью расширения."); 595 NSLog(@"Экземпляр Shape не может вызвать этот метод."); 596} 597 598@end 599 600/////////////////////////////////////// 601// Протоколы 602/////////////////////////////////////// 603// Протокол объявляет методы, которые могут быть реализованы с помощью 604// любого класса. Протоколы сами по себе не являются классами. Они просто 605// определяют интерфейс, который должен быть реализован другими объектами. 606// @protocol имя файла: "CarUtilities.h" 607@protocol CarUtilities <NSObject> // <NSObject> => Имя другого протокола, 608// который включен в этот протокол. 609 @property BOOL engineOn; // Адаптирующий класс должен определить 610// все @synthesize для @property и 611 - (void)turnOnEngine; // определить все методы. 612@end 613// Ниже пример класса, реализующий протокол. 614#import "CarUtilities.h" // Импорт файла с @protocol. 615 616@interface Car : NSObject <CarUtilities> // Внутри <> имя протокола 617// Здесь вам не нужно указывать @property или имена методов для CarUtilities. 618// Они нужны только для @implementation. 619- (void)turnOnEngineWithUtilities:(id <CarUtilities>)car; // Вы также можете 620// указать тип протоколов. 621@end 622// В @implementation нужно реализовать все @property и методы для протокола. 623@implementation Car : NSObject <CarUtilities> 624 625@synthesize engineOn = _engineOn; // Создайте @synthesize-оператор 626// для "@property engineOn". 627 628- (void)turnOnEngine { // Реализуйте turnOnEngine как вам угодно. Протоколы 629// не определят, 630 _engineOn = YES; // как вам реализовать метод, он только требует, 631// чтобы вы реализовали его. 632} 633// Вы можете использовать протокол как данные, если вы знаете, что он реализует 634// методы и переменные. 635- (void)turnOnEngineWithCarUtilities:(id <CarUtilities>)objectOfSomeKind { 636 [objectOfSomeKind engineOn]; // У вас есть доступ к переменным объекта 637 [objectOfSomeKind turnOnEngine]; // и методам. 638 [objectOfSomeKind engineOn]; // Может или не может быть значение YES. Класс 639// реализует как нужно. 640} 641 642@end 643// Экземпляры класса Car сейчас имеют доступ к протоколу. 644Car *carInstance = [[Car alloc] init]; 645[carInstance setEngineOn:NO]; 646[carInstance turnOnEngine]; 647if ([carInstance engineOn]) { 648 NSLog(@"Двигатель запущен."); // напечатает => "Двигатель запущен." 649} 650// Убедитись в том, что объект типа 'id' реализует протокол перед вызовом методов протокола: 651if ([myClass conformsToProtocol:@protocol(CarUtilities)]) { 652 NSLog(@"Не работает, т.к. класс MyClass не реализует протокол CarUtilities."); 653} else if ([carInstance conformsToProtocol:@protocol(CarUtilities)]) { 654 NSLog(@"Работает как класс Car, который реализует протокол CarUtilities."); 655} 656// Категории тоже могут реализовать протоколы: 657// @interface Car (CarCategory) <CarUtilities> 658// Вы можете реализовать много протоколов: 659// @interface Car : NSObject <CarUtilities, CarCleaning> 660// ЗАМЕЧАНИЕ: Если два или более протоколов полагаются друг на друга, 661// убедитесь, что они ранее объявлены: 662#import "Brother.h" 663 664@protocol Brother; // Оператор раннего объявления. Без него компилятор 665// выдаст ошибку. 666 667@protocol Sister <NSObject> 668 669- (void)beNiceToBrother:(id <Brother>)brother; 670 671@end 672 673// Рассмотрите проблему, где протокол Sister полагается на протокол Brother, 674// а Brother полагается на Sister. 675#import "Sister.h" 676 677@protocol Sister; // Эти строки предотвращают рекурсию, решая этим проблему. 678 679@protocol Brother <NSObject> 680 681- (void)beNiceToSister:(id <Sister>)sister; 682 683@end 684 685 686/////////////////////////////////////// 687// Блоки 688/////////////////////////////////////// 689// Блоки - это операторы кода, наподобие функции, которую возможно использовать 690// как данные. 691// Ниже простой блок с целочисленным аргументом, и возвращает аргумент плюс 4. 692int (^addUp)(int n); // Объявите переменную, чтобы сохранить блок. 693void (^noParameterBlockVar)(void); // Пример объявления блока-переменной 694// без аргументов. 695// Блоки имею доступ к переменным в той же области видимости. Но переменные 696// будут только для чтения, и значения переданных в блок станут значением 697// переменной, когда блок создастся. 698int outsideVar = 17; // Если мы редактируем outsideVar после объявления addUp, 699// outsideVar остается равным 17. 700__block long mutableVar = 3; // __block делают переменные перезаписываемыми 701// в блоках, в отличие от outsideVar. 702addUp = ^(int n) { // Удалите (int n) в блоке, чтобы не принимать 703// какие-либо параметры. 704 NSLog(@"Вы можете иметь столько строк в блоке, сколько вы хотели."); 705 NSSet *blockSet; // Также вы можете объявить локальные переменные. 706 mutableVar = 32; // Присвоить новое значение к __block-переменной. 707 return n + outsideVar; // Необязательный оператор возврата. 708} 709int addUp = add(10 + 16); // Вызывает блок кода с аргументами. 710// Блоки часто используются как аргументы функции, чтобы позже их вызвать, или 711// как функции обратного вызова (callbacks). 712@implementation BlockExample : NSObject 713 714- (void)runBlock:(void (^)(NSString))block { 715 NSLog(@"В аргументе блок ничего не возвращает и принимает NSString-объект."); 716 block(@"Аргумент передан блоку на исполнение."); // Вызов блока. 717} 718 719@end 720 721 722/////////////////////////////////////// 723// Управление памятью 724/////////////////////////////////////// 725/* 726Для каждого объекта, используемого в приложении, должна быть выделена память 727для таких объектов. Когда приложение прекращает использование объекта, память 728должна быть освобождена, чтобы гарантировать эффективность приложения. 729Objective-C не использует сборщик мусора, а вместо этого применяет подсчет ссылок. 730Пока существует по крайней мере одна ссылка на объект (также называется 731"владение" объектом), то объект будет доступен к использованию (еще известно 732как "право владения"). 733 734Когда экземпляр владеет объектом, его ссылка увеличивается на один. Когда 735объекта освобождается, счетчик ссылки уменьшается на один. Когда счетчик ссылки 736равен нулю, объект удаляется из памяти. 737 738Над всеми объектами взаимодействуют, следуя паттерну: 739(1) создание объекта, (2) использование объекта, (3) затем освобождение объекта из памяти. 740*/ 741 742MyClass *classVar = [MyClass alloc]; // 'alloc' устанавливает счетчик ссылки 743// объекта classVar на 1 и возвращает указатель на объект. 744[classVar release]; // Уменьшает счетчик ссылки объекта classVar 745// 'retain' заявляет право собственности на существующий экземпляр объекта 746// и увеличивает счетчик ссылки. Затем вернет указатель на объект. 747MyClass *newVar = [classVar retain]; // Если classVar освободится, объект 748// останется в памяти, потому что newVar - владелец 749[classVar autorelease]; // Удалит право на владение объектом 750// в конце @autoreleasepool блока. Вернет указатель на объект. 751 752// @property может использовать 'retain' и 'assign' тоже для маленького 753// удобного определения 754@property (retain) MyClass *instance; // Освободит старое значение и сохранит 755// одно новое (строгая ссылка) 756@property (assign) NSSet *set; // Укажет на новое значение 757// без сохранения/освобождения старого значения (слабая ссылка) 758 759// Автоматический подсчет ссылок (ARC) 760// Управление памятью может быть трудным, поэтому в Xcode 4.2 и iOS 4 введен 761// автоматический подсчет ссылок (ARC). 762// ARC - это особенность компилятора, который помещает "retain", "release" 763// и "autorelease" автоматически за вас тогда, когда используется ARC, 764// вам не нужно больше обращаться к "retain", "release" или "autorelease" 765MyClass *arcMyClass = [[MyClass alloc] init]; 766// ... код, использующий объект arcMyClass 767// Без ARC, вам нужно было бы вызвать: [arcMyClass release] после того, как вы 768// завершите работу с объектом arcMyClass. Но с ARC, 769// теперь этого не нужно делать. Он будет помещать release-вызов за вас 770 771// Что касается 'assign' и 'retain' @property атрибутов, в ARC вы должны 772// использовать 'weak' и 'strong' 773@property (weak) MyClass *weakVar; // 'weak' не принимает право на владение 774// объектом. Если исходный счетчик ссылки экземпляра обнуляется, 775// weakVar-свойство автоматически примет значение nil, 776// во избежание падения приложения 777@property (strong) MyClass *strongVar; // 'strong' принимает право на владение 778// объектом. Гарантирует, что объект останется в памяти для использования 779 780// Для обычных переменных (не объявленных с помощью @property), используйте 781// следующий способ: 782__strong NSString *strongString; // По умолчанию. Переменная сохраняется в памяти, 783// пока она не покинет область видимости 784__weak NSSet *weakSet; // Слабая ссылка на существующий объект. Когда существующий 785// объект освобождается, weakSet принимает nil 786__unsafe_unretained NSArray *unsafeArray; // Похож на __weak, но unsafeArray 787// не принимает nil, когда существующий объект освобождается

На почитать

Wikipedia Objective-C

Learning Objective-C

iOS For High School Students: Getting Started

iOS разработчик: Обзор книг для новичка

Хочешь быть iOS разработчиком? Будь им!