2013-11-22 14:20:35 +00:00
|
|
|
|
---
|
2013-11-22 00:40:12 +00:00
|
|
|
|
language: Objective-C
|
2015-02-26 14:40:57 +00:00
|
|
|
|
filename: LearnObjectiveC-ru.m
|
2013-11-22 00:40:12 +00:00
|
|
|
|
contributors:
|
|
|
|
|
- ["Eugene Yagrushkin", "www.about.me/yagrushkin"]
|
|
|
|
|
- ["Yannick Loriot", "https://github.com/YannickL"]
|
2015-02-26 14:40:57 +00:00
|
|
|
|
- ["Levi Bostian", "https://github.com/levibostian"]
|
2013-11-22 00:40:12 +00:00
|
|
|
|
translators:
|
|
|
|
|
- ["Evlogy Sutormin", "http://evlogii.com"]
|
2015-02-26 14:40:57 +00:00
|
|
|
|
- ["Dmitry Bessonov", "https://github.com/TheDmitry"]
|
2013-11-22 00:40:12 +00:00
|
|
|
|
lang: ru-ru
|
|
|
|
|
---
|
|
|
|
|
|
2015-02-26 14:40:57 +00:00
|
|
|
|
Objective-C — основной язык программирования, используемый корпорацией Apple
|
2021-05-25 11:42:50 +00:00
|
|
|
|
для операционных систем macOS и iOS и их соответствующих фреймворках Cocoa и
|
2015-02-26 14:40:57 +00:00
|
|
|
|
Cocoa Touch.
|
|
|
|
|
Он является объектно-ориентированным языком программирования общего назначения,
|
|
|
|
|
который добавляет обмен сообщениями в Smalltalk-стиле к языку программирования C.
|
2013-11-22 00:40:12 +00:00
|
|
|
|
|
2015-10-09 14:32:05 +00:00
|
|
|
|
```objective-c
|
2015-02-26 14:40:57 +00:00
|
|
|
|
// Однострочные комментарии начинаются с //
|
2013-11-22 00:40:12 +00:00
|
|
|
|
|
|
|
|
|
/*
|
2015-02-26 14:40:57 +00:00
|
|
|
|
Так выглядят многострочные комментарии
|
2013-11-22 00:40:12 +00:00
|
|
|
|
*/
|
|
|
|
|
|
2015-02-26 14:40:57 +00:00
|
|
|
|
// Импорт заголовочных файлов фреймворка Foundation с помощью #import
|
|
|
|
|
// Используйте <>, чтобы импортировать глобальные файлы (обычно фреймворки)
|
|
|
|
|
// Используйте "", чтобы импортировать локальные файлы (из проекта)
|
2013-11-22 00:40:12 +00:00
|
|
|
|
#import <Foundation/Foundation.h>
|
|
|
|
|
#import "MyClass.h"
|
|
|
|
|
|
2015-02-26 14:40:57 +00:00
|
|
|
|
// Если вы включили модули для iOS >= 7.0 или OS X >= 10.9 проектов в
|
|
|
|
|
// Xcode 5, вы можете импортировать фреймворки подобным образом:
|
|
|
|
|
@import Foundation;
|
|
|
|
|
|
|
|
|
|
// Точка входа в программу - это функция main,
|
|
|
|
|
// которая возвращает целый тип
|
2013-11-22 00:40:12 +00:00
|
|
|
|
int main (int argc, const char * argv[])
|
|
|
|
|
{
|
2015-02-26 14:40:57 +00:00
|
|
|
|
// Создание autorelease pool для управления памятью в программе
|
2013-11-22 00:40:12 +00:00
|
|
|
|
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
|
2015-02-26 14:40:57 +00:00
|
|
|
|
// В место этого воспользуйтесь @autoreleasepool, если вы используете
|
|
|
|
|
// автоматический подсчет ссылок (ARC)
|
|
|
|
|
@autoreleasepool {
|
|
|
|
|
|
2013-11-22 00:40:12 +00:00
|
|
|
|
// Используйте NSLog для печати в консоль
|
2015-02-26 14:40:57 +00:00
|
|
|
|
NSLog(@"Привет Мир!"); // Напечатает строку "Привет Мир!"
|
2013-11-22 00:40:12 +00:00
|
|
|
|
|
|
|
|
|
///////////////////////////////////////
|
|
|
|
|
// Типы и переменные
|
|
|
|
|
///////////////////////////////////////
|
|
|
|
|
|
2015-02-26 14:40:57 +00:00
|
|
|
|
// Объявление простых типов
|
2013-11-22 00:40:12 +00:00
|
|
|
|
int myPrimitive1 = 1;
|
|
|
|
|
long myPrimitive2 = 234554664565;
|
|
|
|
|
|
2015-02-26 14:40:57 +00:00
|
|
|
|
// Объявление объектов
|
2013-11-22 00:40:12 +00:00
|
|
|
|
// Помещайте * в начало названия объекта для строго типизированного объявления
|
|
|
|
|
MyClass *myObject1 = nil; // Строгая типизация
|
|
|
|
|
id myObject2 = nil; // Слабая типизация
|
|
|
|
|
// %@ – это объект
|
2015-02-26 14:40:57 +00:00
|
|
|
|
// 'description' - это общий для всех объектов метод вывода данных
|
|
|
|
|
NSLog(@"%@ and %@", myObject1, [myObject2 description]); // напечатает "(null) and (null)"
|
2013-11-22 00:40:12 +00:00
|
|
|
|
|
|
|
|
|
// Строка
|
2015-02-26 14:40:57 +00:00
|
|
|
|
NSString *worldString = @"Мир";
|
|
|
|
|
NSLog(@"Привет %@!", worldString); // напечатает "Привет Мир!"
|
|
|
|
|
// NSMutableString - это изменяемая версия NSString-объекта
|
|
|
|
|
NSMutableString *mutableString = [NSMutableString stringWithString:@"Привет"];
|
|
|
|
|
[mutableString appendString:@" Мир!"];
|
|
|
|
|
NSLog(@"%@", mutableString); // напечатает => "Привет Мир!"
|
2013-11-22 00:40:12 +00:00
|
|
|
|
|
|
|
|
|
// Символьные литералы
|
|
|
|
|
NSNumber *theLetterZNumber = @'Z';
|
2015-02-26 14:40:57 +00:00
|
|
|
|
char theLetterZ = [theLetterZNumber charValue]; // или 'Z'
|
2013-11-22 00:40:12 +00:00
|
|
|
|
NSLog(@"%c", theLetterZ);
|
|
|
|
|
|
2015-02-26 14:40:57 +00:00
|
|
|
|
// Целочисленные литералы
|
2013-11-22 00:40:12 +00:00
|
|
|
|
NSNumber *fortyTwoNumber = @42;
|
2015-02-26 14:40:57 +00:00
|
|
|
|
int fortyTwo = [fortyTwoNumber intValue]; // или '42'
|
2013-11-22 00:40:12 +00:00
|
|
|
|
NSLog(@"%i", fortyTwo);
|
|
|
|
|
|
|
|
|
|
// Беззнаковый целочисленный литерал
|
|
|
|
|
NSNumber *fortyTwoUnsignedNumber = @42U;
|
2015-02-26 14:40:57 +00:00
|
|
|
|
unsigned int fortyTwoUnsigned = [fortyTwoUnsignedNumber unsignedIntValue]; // или 42
|
2013-11-22 00:40:12 +00:00
|
|
|
|
NSLog(@"%u", fortyTwoUnsigned);
|
|
|
|
|
|
|
|
|
|
NSNumber *fortyTwoShortNumber = [NSNumber numberWithShort:42];
|
2015-02-26 14:40:57 +00:00
|
|
|
|
short fortyTwoShort = [fortyTwoShortNumber shortValue]; // или 42
|
2013-11-22 00:40:12 +00:00
|
|
|
|
NSLog(@"%hi", fortyTwoShort);
|
|
|
|
|
|
2015-02-26 14:40:57 +00:00
|
|
|
|
NSNumber *fortyOneShortNumber = [NSNumber numberWithShort:41];
|
|
|
|
|
unsigned short fortyOneUnsigned = [fortyOneShortNumber unsignedShortValue]; // или 41
|
|
|
|
|
NSLog(@"%u", fortyOneUnsigned);
|
|
|
|
|
|
2013-11-22 00:40:12 +00:00
|
|
|
|
NSNumber *fortyTwoLongNumber = @42L;
|
2015-02-26 14:40:57 +00:00
|
|
|
|
long fortyTwoLong = [fortyTwoLongNumber longValue]; // или 42
|
2013-11-22 00:40:12 +00:00
|
|
|
|
NSLog(@"%li", fortyTwoLong);
|
2015-02-26 14:40:57 +00:00
|
|
|
|
|
|
|
|
|
NSNumber *fiftyThreeLongNumber = @53L;
|
|
|
|
|
unsigned long fiftyThreeUnsigned = [fiftyThreeLongNumber unsignedLongValue]; // или 53
|
|
|
|
|
NSLog(@"%lu", fiftyThreeUnsigned);
|
2013-11-22 00:40:12 +00:00
|
|
|
|
|
|
|
|
|
// Вещественный литерал
|
|
|
|
|
NSNumber *piFloatNumber = @3.141592654F;
|
2015-02-26 14:40:57 +00:00
|
|
|
|
float piFloat = [piFloatNumber floatValue]; // или 3.141592654f
|
|
|
|
|
NSLog(@"%f", piFloat); // напечатает 3.141592654
|
|
|
|
|
NSLog(@"%5.2f", piFloat); // напечатает " 3.14"
|
2013-11-22 00:40:12 +00:00
|
|
|
|
|
|
|
|
|
NSNumber *piDoubleNumber = @3.1415926535;
|
2015-02-26 14:40:57 +00:00
|
|
|
|
double piDouble = [piDoubleNumber doubleValue]; // или 3.1415926535
|
2013-11-22 00:40:12 +00:00
|
|
|
|
NSLog(@"%f", piDouble);
|
2015-02-26 14:40:57 +00:00
|
|
|
|
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 - изменяемый
|
|
|
|
|
|
2013-11-22 00:40:12 +00:00
|
|
|
|
// BOOL (булевый) литерал
|
|
|
|
|
NSNumber *yesNumber = @YES;
|
|
|
|
|
NSNumber *noNumber = @NO;
|
2015-02-26 14:40:57 +00:00
|
|
|
|
// или
|
|
|
|
|
BOOL yesBool = YES;
|
|
|
|
|
BOOL noBool = NO;
|
|
|
|
|
NSLog(@"%i", yesBool); // напечатает 1
|
|
|
|
|
|
2013-11-22 00:40:12 +00:00
|
|
|
|
// Массив
|
2015-02-26 14:40:57 +00:00
|
|
|
|
// Может содержать различные типы данных, но должен быть объектом Objective-C
|
2013-11-22 00:40:12 +00:00
|
|
|
|
NSArray *anArray = @[@1, @2, @3, @4];
|
|
|
|
|
NSNumber *thirdNumber = anArray[2];
|
2015-02-26 14:40:57 +00:00
|
|
|
|
NSLog(@"Третье число = %@", thirdNumber); // Напечатает "Третье число = 3"
|
|
|
|
|
// NSMutableArray - это изменяемая версия NSArray, допускающая вам изменять
|
|
|
|
|
// элементы в массиве и расширять или сокращать массив.
|
|
|
|
|
// Удобный, но не эффективный как NSArray.
|
|
|
|
|
NSMutableArray *mutableArray = [NSMutableArray arrayWithCapacity:2];
|
|
|
|
|
[mutableArray addObject:@"Привет"];
|
|
|
|
|
[mutableArray addObject:@"Мир"];
|
|
|
|
|
[mutableArray removeObjectAtIndex:0];
|
|
|
|
|
NSLog(@"%@", [mutableArray objectAtIndex:0]); // напечатает "Мир"
|
2013-11-22 00:40:12 +00:00
|
|
|
|
|
|
|
|
|
// Словарь
|
2015-02-26 14:40:57 +00:00
|
|
|
|
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); // напечатает => {(Привет)}
|
|
|
|
|
|
2013-11-22 00:40:12 +00:00
|
|
|
|
///////////////////////////////////////
|
|
|
|
|
// Операторы
|
|
|
|
|
///////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
// Операторы работают также как в Си.
|
|
|
|
|
// Например:
|
|
|
|
|
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)
|
|
|
|
|
{
|
2015-02-26 14:40:57 +00:00
|
|
|
|
NSLog(@"Я никогда не выполнюсь");
|
2013-11-22 00:40:12 +00:00
|
|
|
|
} else if (0)
|
|
|
|
|
{
|
2015-02-26 14:40:57 +00:00
|
|
|
|
NSLog(@"Я тоже никогда не выполнюсь");
|
2013-11-22 00:40:12 +00:00
|
|
|
|
} else
|
|
|
|
|
{
|
2015-02-26 14:40:57 +00:00
|
|
|
|
NSLog(@"Я напечатаюсь");
|
2013-11-22 00:40:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Ветвление с множественным выбором
|
|
|
|
|
switch (2)
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
{
|
2015-02-26 14:40:57 +00:00
|
|
|
|
NSLog(@"Я никогда не выполнюсь");
|
2013-11-22 00:40:12 +00:00
|
|
|
|
} break;
|
|
|
|
|
case 1:
|
|
|
|
|
{
|
2015-02-26 14:40:57 +00:00
|
|
|
|
NSLog(@"Я тоже никогда не выполнюсь");
|
2013-11-22 00:40:12 +00:00
|
|
|
|
} break;
|
|
|
|
|
default:
|
|
|
|
|
{
|
2015-02-26 14:40:57 +00:00
|
|
|
|
NSLog(@"Я напечатаюсь");
|
2013-11-22 00:40:12 +00:00
|
|
|
|
} 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,"
|
|
|
|
|
|
2015-02-26 14:40:57 +00:00
|
|
|
|
// Цикл просмотра
|
2013-11-22 00:40:12 +00:00
|
|
|
|
NSArray *values = @[@0, @1, @2, @3];
|
|
|
|
|
for (NSNumber *value in values)
|
|
|
|
|
{
|
|
|
|
|
NSLog(@"%@,", value);
|
|
|
|
|
} // => напечатает "0,"
|
|
|
|
|
// "1,"
|
|
|
|
|
// "2,"
|
|
|
|
|
// "3,"
|
|
|
|
|
|
2015-02-26 14:40:57 +00:00
|
|
|
|
// Цикл for для объектов. Может использоваться с любым объектом Objective-C
|
|
|
|
|
for (id item in values) {
|
|
|
|
|
NSLog(@"%@,", item);
|
|
|
|
|
} // напечатает => "0,"
|
|
|
|
|
// "1,"
|
|
|
|
|
// "2,"
|
|
|
|
|
// "3,"
|
|
|
|
|
|
2013-11-22 00:40:12 +00:00
|
|
|
|
// Обработка исключений
|
|
|
|
|
@try
|
|
|
|
|
{
|
|
|
|
|
// Ваше исключение здесь
|
|
|
|
|
@throw [NSException exceptionWithName:@"FileNotFoundException"
|
2015-02-26 14:40:57 +00:00
|
|
|
|
reason:@"Файл не найден в системе" userInfo:nil];
|
2013-11-22 00:40:12 +00:00
|
|
|
|
} @catch (NSException * e)
|
|
|
|
|
{
|
2015-02-26 14:40:57 +00:00
|
|
|
|
NSLog(@"Исключение: %@", e);
|
2013-11-22 00:40:12 +00:00
|
|
|
|
} @finally
|
|
|
|
|
{
|
2015-02-26 14:40:57 +00:00
|
|
|
|
NSLog(@"В конце отводится время для очистки.");
|
|
|
|
|
} // => напечатает "Исключение: Файл не найден в системе"
|
|
|
|
|
// "В конце отводится время для очистки."
|
|
|
|
|
|
|
|
|
|
// NSError - это полезные объекты для аргументов функции, чтобы заполнить их
|
|
|
|
|
// пользовательскими ошибками.
|
|
|
|
|
NSError *error = [NSError errorWithDomain:@"Неправильный эл. адрес." code:4 userInfo:nil];
|
2013-11-22 00:40:12 +00:00
|
|
|
|
|
|
|
|
|
///////////////////////////////////////
|
|
|
|
|
// Объекты
|
|
|
|
|
///////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
// Создание объектов через выделение памяти и инициализацию.
|
|
|
|
|
// Объект не является полнофункциональным пока обе части не выполнятся.
|
|
|
|
|
MyClass *myObject = [[MyClass alloc] init];
|
|
|
|
|
|
2015-02-26 14:40:57 +00:00
|
|
|
|
// В Objective-C модель ООП базируется на передаче сообщений.
|
2013-11-22 00:40:12 +00:00
|
|
|
|
// В Objective-C Вы не просто вызваете метод; вы посылаете сообщение.
|
2015-02-26 14:40:57 +00:00
|
|
|
|
[myObject instanceMethodWithParameter:@"Стив Джобс"];
|
2013-11-22 00:40:12 +00:00
|
|
|
|
|
|
|
|
|
// Очищайте память, перед завершением работы программы.
|
|
|
|
|
[pool drain];
|
|
|
|
|
|
2015-02-26 14:40:57 +00:00
|
|
|
|
// Конец @autoreleasepool
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-22 00:40:12 +00:00
|
|
|
|
// Конец программы.
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////
|
|
|
|
|
// Классы и функции
|
|
|
|
|
///////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
// Объявляйте свой класс в файле МойКласс.h
|
|
|
|
|
// Синтаксис объявления:
|
|
|
|
|
// @interface ИмяКласса : ИмяКлассаРодителя <ИмплементируемыеПротоколы>
|
|
|
|
|
// {
|
2015-02-26 14:40:57 +00:00
|
|
|
|
// тип имя; <= Объявление переменных;
|
2013-11-22 00:40:12 +00:00
|
|
|
|
// }
|
2015-02-26 14:40:57 +00:00
|
|
|
|
// @property тип имя; <= объявление свойств
|
2013-11-22 00:40:12 +00:00
|
|
|
|
// -/+ (тип) Объявление метода(ов).
|
|
|
|
|
// @end
|
2015-02-26 14:40:57 +00:00
|
|
|
|
@interface MyClass : NSObject <MyProtocol> // NSObject - это базовый класс в Objective-C.
|
2013-11-22 00:40:12 +00:00
|
|
|
|
{
|
2015-02-26 14:40:57 +00:00
|
|
|
|
// Объявления экземпляров переменных (может существовать в файлах интерфейса или реализвации)
|
|
|
|
|
int count; // По умолчанию защищенный доступ.
|
|
|
|
|
@private id data; // Приватный доступ (Намного удобнее объявлять в файле реализации)
|
2013-11-22 00:40:12 +00:00
|
|
|
|
NSString *name;
|
|
|
|
|
}
|
2015-02-26 14:40:57 +00:00
|
|
|
|
// Удобное обозначение для переменных с открытым (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;
|
2013-11-22 00:40:12 +00:00
|
|
|
|
|
|
|
|
|
// Методы
|
2015-02-26 14:40:57 +00:00
|
|
|
|
+/- (возвращаемый тип)сигнатураМетода:(Параметр типа *)имяПараметра;
|
2013-11-22 00:40:12 +00:00
|
|
|
|
|
|
|
|
|
// + для методов класса
|
|
|
|
|
+ (NSString *)classMethod;
|
2015-02-26 14:40:57 +00:00
|
|
|
|
+ (MyClass *)myClassFromHeight:(NSNumber *)defaultHeight;
|
2013-11-22 00:40:12 +00:00
|
|
|
|
|
2015-02-26 14:40:57 +00:00
|
|
|
|
// - для методов объекта
|
2013-11-22 00:40:12 +00:00
|
|
|
|
- (NSString *)instanceMethodWithParameter:(NSString *)string;
|
|
|
|
|
- (NSNumber *)methodAParameterAsString:(NSString*)string andAParameterAsNumber:(NSNumber *)number;
|
|
|
|
|
|
2015-02-26 14:40:57 +00:00
|
|
|
|
// Методы-конструктор с аргументом:
|
|
|
|
|
- (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));
|
|
|
|
|
}
|
2013-11-22 00:40:12 +00:00
|
|
|
|
|
2015-09-24 14:11:45 +00:00
|
|
|
|
// Имплементируйте методы в файле MyClass.m:
|
2015-02-26 14:40:57 +00:00
|
|
|
|
@implementation MyClass {
|
|
|
|
|
long distance; // Переменная экземпляра с закрытым (private) доступом
|
|
|
|
|
NSNumber height;
|
|
|
|
|
}
|
2013-11-22 00:40:12 +00:00
|
|
|
|
|
2015-12-04 04:12:54 +00:00
|
|
|
|
// Для доступа к public переменной, объявленной в интерфейсе, используйте '_' перед названием переменной:
|
2015-09-24 14:11:45 +00:00
|
|
|
|
_count = 5; // Ссылается на "int count" из интерфейса MyClass
|
2015-12-04 04:12:54 +00:00
|
|
|
|
// Получение доступа к переменной, объявленной в реализации происходит следующим образом:
|
|
|
|
|
distance = 18; // Ссылается на "long distance" из реализации MyClass
|
2015-09-24 14:23:49 +00:00
|
|
|
|
// Для использования в иплементации переменной, объявленной в интерфейсе с помощью @property,
|
|
|
|
|
// следует использовать @synthesize для создания переменной аксессора:
|
2015-12-04 04:12:54 +00:00
|
|
|
|
@synthesize roString = _roString; // Теперь _roString доступна в @implementation (реализации интерфейса)
|
2015-02-26 14:40:57 +00:00
|
|
|
|
|
2015-09-24 14:11:45 +00:00
|
|
|
|
// Вызывается в первую очередь, перед вызовом других медотов класса или инициализации других объектов
|
2015-02-26 14:40:57 +00:00
|
|
|
|
+ (void)initialize
|
|
|
|
|
{
|
|
|
|
|
if (self == [MyClass class]) {
|
|
|
|
|
distance = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-11-22 00:40:12 +00:00
|
|
|
|
|
|
|
|
|
// Вызывается при высвобождении памяти под объектом
|
|
|
|
|
- (void)dealloc
|
|
|
|
|
{
|
2015-02-26 14:40:57 +00:00
|
|
|
|
[height release]; // Если не используется ARC, убедитесь в освобождении переменных объекта класса
|
|
|
|
|
[super dealloc]; // and call parent class dealloc
|
2013-11-22 00:40:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-02-26 14:40:57 +00:00
|
|
|
|
// Конструкторы – это способ создания объектов класса.
|
|
|
|
|
// Это конструктор по умолчанию, который вызывается, когда объект инициализируется.
|
2013-11-22 00:40:12 +00:00
|
|
|
|
- (id)init
|
|
|
|
|
{
|
2015-02-26 14:40:57 +00:00
|
|
|
|
if ((self = [super init])) // 'super' используется для того, чтобы обратиться к методам родительского класса
|
2013-11-22 00:40:12 +00:00
|
|
|
|
{
|
2015-02-26 14:40:57 +00:00
|
|
|
|
self.count = 1; // 'self' используется для вызова самого себя
|
2013-11-22 00:40:12 +00:00
|
|
|
|
}
|
|
|
|
|
return self;
|
|
|
|
|
}
|
2015-02-26 14:40:57 +00:00
|
|
|
|
// Можно создать конструкторы, которые содержат аргументы:
|
|
|
|
|
- (id)initWithDistance:(int)defaultDistance
|
|
|
|
|
{
|
|
|
|
|
distance = defaultDistance;
|
|
|
|
|
return self;
|
|
|
|
|
}
|
2013-11-22 00:40:12 +00:00
|
|
|
|
|
|
|
|
|
+ (NSString *)classMethod
|
|
|
|
|
{
|
|
|
|
|
return [[self alloc] init];
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-26 14:40:57 +00:00
|
|
|
|
+ (MyClass *)myClassFromHeight:(NSNumber *)defaultHeight
|
|
|
|
|
{
|
|
|
|
|
height = defaultHeight;
|
|
|
|
|
return [[self alloc] init];
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-22 00:40:12 +00:00
|
|
|
|
- (NSString *)instanceMethodWithParameter:(NSString *)string
|
|
|
|
|
{
|
2015-02-26 14:40:57 +00:00
|
|
|
|
return @"Новая строка";
|
2013-11-22 00:40:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSNumber *)methodAParameterAsString:(NSString*)string andAParameterAsNumber:(NSNumber *)number
|
|
|
|
|
{
|
|
|
|
|
return @42;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-26 14:40:57 +00:00
|
|
|
|
// Objective-C не содержит объявление приватных методов, но вы можете имитировать их.
|
|
|
|
|
// Чтобы сымитировать приватный метод, создайте метод в @implementation, но не в @interface.
|
|
|
|
|
- (NSNumber *)secretPrivateMethod {
|
|
|
|
|
return @72;
|
|
|
|
|
}
|
|
|
|
|
[self secretPrivateMethod]; // Вызывает приватный метод
|
|
|
|
|
|
2013-11-22 00:40:12 +00:00
|
|
|
|
// Методы объявленные в МyProtocol (см. далее)
|
|
|
|
|
- (void)myProtocolMethod
|
|
|
|
|
{
|
2015-02-26 14:40:57 +00:00
|
|
|
|
// операторы
|
2013-11-22 00:40:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-02-26 14:40:57 +00:00
|
|
|
|
@end // Устанавливает конец реализации (implementation)
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////
|
|
|
|
|
// Категории
|
|
|
|
|
///////////////////////////////////////
|
|
|
|
|
// Категория - это группа методов предназначенные для того, чтобы расширить класс. Они позволяют вам добавить новые методы
|
|
|
|
|
// к существующему классу для организационных целей. Это не стоит путать с подклассами.
|
|
|
|
|
// Подклассы предназначены для ИЗМЕНЕНИЯ функциональности объекта пока как категории ДОБАВЛЯЮТ
|
|
|
|
|
// функциональность в объект.
|
|
|
|
|
// Категории позволяют вам:
|
|
|
|
|
// -- Добавлять методы в существующий класс для организационных целей.
|
|
|
|
|
// -- Допускает вам расширять объекты Objective-C классов (напр.: NSString) добавить ваши собственные методы.
|
|
|
|
|
// -- Добавляет возможность создать защищенные и закрытые методы классов.
|
|
|
|
|
// ПРИМЕЧАНИЕ: Не переопределяйте методы базового класса в категории даже если у вас есть возможность это сделать
|
|
|
|
|
// to. Переопределение методов может привести к ошибкам компиляции позднее между различными категориями и это
|
|
|
|
|
// нарушает цель категорий, чтобы добавлять только функциональность. Вместо этого подклассы переопределяют методы.
|
|
|
|
|
|
|
|
|
|
// Здесь простой базовый класс Car.
|
|
|
|
|
@interface Car : NSObject
|
|
|
|
|
|
|
|
|
|
@property NSString *make;
|
|
|
|
|
@property NSString *color;
|
|
|
|
|
|
|
|
|
|
- (void)turnOn;
|
|
|
|
|
- (void)accelerate;
|
|
|
|
|
|
2013-11-22 00:40:12 +00:00
|
|
|
|
@end
|
|
|
|
|
|
2015-02-26 14:40:57 +00:00
|
|
|
|
// И реализация базового класса Car:
|
|
|
|
|
#import "Car.h"
|
|
|
|
|
|
|
|
|
|
@implementation Car
|
|
|
|
|
|
|
|
|
|
@synthesize make = _make;
|
|
|
|
|
@synthesize color = _color;
|
|
|
|
|
|
|
|
|
|
- (void)turnOn {
|
|
|
|
|
NSLog(@"Машина заведена.");
|
|
|
|
|
}
|
|
|
|
|
- (void)accelerate {
|
|
|
|
|
NSLog(@"Ускорение.");
|
|
|
|
|
}
|
2013-11-22 00:40:12 +00:00
|
|
|
|
|
|
|
|
|
@end
|
2015-02-26 14:40:57 +00:00
|
|
|
|
|
2015-09-24 14:11:45 +00:00
|
|
|
|
// Теперь, если мы хотим создать объект Truck - грузовик, мы должны создать подкласс класса Car, что
|
2022-03-15 22:43:39 +00:00
|
|
|
|
// изменит функциональность Car и позволит вести себя подобно грузовику. Но что, если мы хотим только добавить
|
|
|
|
|
// определенную функциональность в уже существующий класс Car? Например - чистка автомобиля. Мы просто создадим
|
2015-09-24 14:11:45 +00:00
|
|
|
|
// категорию, которая добавит несколько методов для чистки автомобиля в класс Car:
|
2015-02-26 14:40:57 +00:00
|
|
|
|
// @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,
|
2017-08-23 08:14:39 +00:00
|
|
|
|
// вам не нужно больше обращаться к "retain", "release" или "autorelease"
|
2015-02-26 14:40:57 +00:00
|
|
|
|
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' принимает право на владение
|
2015-09-24 14:11:45 +00:00
|
|
|
|
// объектом. Гарантирует, что объект останется в памяти для использования
|
2015-02-26 14:40:57 +00:00
|
|
|
|
|
|
|
|
|
// Для обычных переменных (не объявленных с помощью @property), используйте
|
|
|
|
|
// следующий способ:
|
|
|
|
|
__strong NSString *strongString; // По умолчанию. Переменная сохраняется в памяти,
|
|
|
|
|
// пока она не покинет область видимости
|
|
|
|
|
__weak NSSet *weakSet; // Слабая ссылка на существующий объект. Когда существующий
|
|
|
|
|
// объект освобождается, weakSet принимает nil
|
|
|
|
|
__unsafe_unretained NSArray *unsafeArray; // Похож на __weak, но unsafeArray
|
|
|
|
|
// не принимает nil, когда существующий объект освобождается
|
2013-11-22 00:40:12 +00:00
|
|
|
|
```
|
2024-04-06 15:33:50 +00:00
|
|
|
|
|
2013-11-22 00:40:12 +00:00
|
|
|
|
## На почитать
|
|
|
|
|
|
|
|
|
|
[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/)
|