Objective-C
Разработка приложений для iOS
Лекция 1
Глеб Тарасов
Мобильная разработка, что изменилось?
Особенности
• Высокие ожидания пользователей• Другие паттерны использования
• Маленький экран• Слабый процессор, мало памяти• Медленный интернет• Управление жестами
Почему iOS?
Разработка под iOS
XCode
Mac OS Lion
Как запустить Mac OS?
•Компьютер Mac
•Hacintosh
•Виртуалка (VMWare, VirtualBox)
Apple Developer Program
$99
• Отладка на устройстве• Выпуск в AppStore
Objective-C
История1981 — Object-Oriented Pre-Compiler (OOPC). Компания StepStone. Tom Love & Brad Cox
1996 — Apple покупает NeXT. Objective-C — основной язык для Mac OS.
1988 — NeXT лицензирует Objective-C
1986 — Objective-C. «Object-Oriented Programming, An Evolutionary Approach» (Brad Cox).
2007 — Objective-C — основной язык для iPhone OS
Основные особенности
• объектно-ориентированный• компилируется в машинный код• полностью совместим с Си
• слабо-типизированный• управление памятью основано на счетчике ссылок
Сначала немного Си
http://ru.wikipedia.org/wiki/Си_(язык_программирования)
Указателиint main(int argc, const char * argv[]){ int a = 5; int *b = &a; *b = 7; printf("%d", a);}
7
double add(double a, double b){ return a + b;}
int main(int argc, const char * argv[]){ double a = 5.5; double b = 7; double *arr = malloc(2 * sizeof(double)); arr[0] = a; arr[1] = b; printf("array [0] = %g, [1] = %g, add = %g", arr[0], arr[1], add(arr[0], arr[1])); free(arr);}
Функции
Структурыtypedef struct{ float x; float y;} Location;
double add(double a, double b){ return a + b;}
Location createLocation(float x, float y){ Location l; l.x = x; l.y = y; return l;}
int main(int argc, const char * argv[]){ Location l = createLocation(1.5, 0.5); printf("location: {%g, %g}", l.x, l.y);}
Перечисленияtypedef enum { UIViewAnimationCurveEaseInOut, UIViewAnimationCurveEaseIn, UIViewAnimationCurveEaseOut, UIViewAnimationCurveLinear} UIViewAnimationCurve;
UIViewAnimationCurve a = UIViewAnimationCurveLinear;printf("%d", a);
ПамятьКучаСтек
{ int a = 10;}{ int a = 20;}
int *a = malloc(sizeof(int) * 10);
free(a);
Теперь немного ООП
http://ru.wikipedia.org/wiki/Объектно-ориентированное_программирование
Класс - описание внутреннего состояния + методов изменения этого состояния
Объект - экземпляр класса
Поля - состояние объекта
Методы - изменение состояния объекта
Класс «Работник»
- имя (строка)- возраст (целое)- пол (м/ж)- время_поступления_на_работу (дата)- время_увольнения (дата)- подчиненные (массив работников)
- уволить()- добавить подчиненного(работник)
Поля:
Методы:
НаследованиеКласс «Руководитель» (наследуется от «Работник»)
- подчиненные (массив работников)
- добавить подчиненного(работник)
Поля:
Методы:
Objective-C
NSString *a = [[NSString alloc] init];
NSString *b = [a copy];
[b stringByReplacingOccurrencesOfString:@" " withString:@""];
NSString *c = @"string";
[c stringByPaddingToLength:20 withString:@" " startingAtIndex:0];
Синтаксис
nil
• аналог null из других языков
• можно вызывать любой метод, не будет исключения
• если метод возвращает объект - вернется nil
• если метод возвращает число - вернется 0• если метод возвращает структуру - результат не определен
nil
NSString *a = nil;int length = [a length]; // 0NSString *m = [a mutableCopy]; // nilNSRange range = [a rangeOfString:@"a"]; // undefined!!!if (a) // if (a != nil){ NSRange r = [a rangeOfString:@"a"];}
BOOL
BOOL a = YES;if (a) // if (a == YES){ BOOL b = [c isEqual:d]; if (!b) // if (a == NO) { //blabla }}
ЧислаCGFloat a = 0.5;NSInteger b = -1;NSUInteger q = 10;
СтруктурыCGPoint p;p.x = 10;p.y = 20;p = CGPointMake(10, 20);
CGSize s;s.width = 100;s.height = 100;s = CGSizeMake(100, 100);
CGRect r;r.size = s;r.origin = p;r = CGRectMake(10, 20, 100, 100);
Стандартные классы
Строки
NSString NSMutableString
NSString *a = @"abc";NSString *b = [a stringByReplacingOccurrencesOfString:@"a" withString:@"b"];NSLog(@"b: %@", b);
NSMutableString *m = [b mutableCopy];NSRange r;r.length = m.length;r.location = 0;[m replaceOccurrencesOfString:@"c" withString:@"b" options:0 range:r];NSLog(@"m: %@", m);
Списки
NSArray NSMutableArray
NSArray *a = [NSArray arrayWithObjects:@"a", @"b", @"c", nil];NSString *first = [a objectAtIndex:0];NSString *last = [a objectAtIndex:[a count] - 1];
NSMutableArray *b = [a mutableCopy];[b addObject:@"r"];[b replaceObjectAtIndex:1 withObject:@"q"];[b removeObjectAtIndex:2];
Обычные упорядоченные массивы
Словари
NSDictionary NSMutableDictionary
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys: @"a", @"key1", @"b", @"key2", nil];NSString *first = [dict objectForKey:@"key1"];
NSMutableDictionary *m = [dict mutableCopy];[m setObject:@"c" forKey:@"key3"];[m setObject:@"aa" forKey:@"key1"];NSLog(@"m: %@", m);
Хранение пар «ключ-значение».Быстрый поиск значения по ключу
Множества
NSSet NSMutableSet
NSSet *s = [NSSet setWithObjects:@"a", @"b", @"c", nil];BOOL c = [s containsObject:@"b"];
NSMutableSet *m = [s mutableCopy];[m addObject:@"d"];[m removeObject:@"a"];
Неупорядоченная коллекция. Быстрая проверка на contains
Перечисление (enumeration)NSArray *arr = [NSArray arrayWithObjects: @"a", @"b", @"c", nil];
for (NSString *a in arr) { NSLog(@"%@", a);}
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys: @"a", @"key1", @"b", @"key2", nil];
for (NSString *key in dict){ NSString *value = [dict objectForKey:key]; NSLog(@"%@ - %@", key, value);}
ЧислаNSNumber
NSNumber *a = [NSNumber numberWithInt:3];int b = [a intValue];
NSNumber *c = [NSNumber numberWithFloat:2.5f];float d = [c floatValue];
NSNumber *e = [NSNumber numberWithDouble:3.567];double f = [e doubleValue];
if ([a isEqualToNumber:c]) NSLog(@"equals");
Бинарные данные
NSData NSMutableData
NSData *data = [[NSData alloc] initWithContentsOfFile:@"data.txt"];NSInteger length = [data length];[data writeToFile:@"result.txt" atomically:YES]; NSMutableData *m = [data mutableCopy];[m appendData:data];
Хранение картинок, текстовых данных в бинарном виде и т.д.
NSNull
NSMutableArray *a = [[NSMutableArray alloc] init];[a addObject:[NSNull null]];
NSObject *q = [a lastObject];if (q == [NSNull null]){ //bla bla}
сохранять «пусто» в массивы и словари
NSValue
CGPoint p = CGPointMake(10, 20);CGRect r = CGRectMake(10, 20, 30, 40);NSValue *v1 = [NSValue valueWithCGPoint:p];NSValue *v2 = [NSValue valueWithCGRect:r];
NSArray *arr = [NSArray arrayWithObjects:v1, v2, nil];CGRect r2 = [[arr lastObject] CGRectValue];
преобразовывать структуры и другие «не объекты» в объекты
Dot notationКласс Rectangle
- float width (число)- float height (число)- Location location (структура)
Rectangle *r = [[Rectangle alloc] init];[r setWidth:10];[r setHeight:20];
Location l;l.x = 1;l.y = 2;
[r setLocation:l];
NSLog(@"%g, %g, (%g, %g)", [r width], [r height], [r location].x, [r location].y);
Dot notation
Rectangle *r = [[Rectangle alloc] init];r.width = 10;r.height = 20;Location l = {1, 2};r.location = l;
NSLog(@"%g, %g, (%g, %g)", r.width, r.height, r.location.x, r.location.y);
Собственные классы
Собственные классы
User.h
Собственные классы@interface User
@end
User.h
Собственные классы@interface User
@end
User.h
: NSObject
Собственные классы@interface User
@end
User.h
{ NSString *_name;}
: NSObject
Собственные классы@interface User
@end
User.h
{ NSString *_name;}
- (void)setName:(NSString *)name;- (NSString *)name;
: NSObject
Собственные классы@interface User
@end
User.h
User.m
{ NSString *_name;}
- (void)setName:(NSString *)name;- (NSString *)name;
: NSObject
Собственные классы@interface User
@end
@implementation User
@end
User.h
User.m
{ NSString *_name;}
- (void)setName:(NSString *)name;- (NSString *)name;
: NSObject
Собственные классы@interface User
@end
@implementation User
@end
User.h
User.m
{ NSString *_name;}
- (void)setName:(NSString *)name;- (NSString *)name;
- (void)setName:(NSString *)name{ _name = name; }
- (NSString *)name{ return _name;}
: NSObject
User.h
User.h#import <Foundation/Foundation.h>
User.h@interface User
@end
#import <Foundation/Foundation.h>
User.h@interface User
@end
#import <Foundation/Foundation.h>
: NSObject
User.h@interface User
@end
#import <Foundation/Foundation.h>
: NSObject
{ NSInteger _age;}
User.h@interface User
@end
#import <Foundation/Foundation.h>
@property(nonatomic, strong) NSString *name;
@property(nonatomic) NSInteger age;
: NSObject
{ NSInteger _age;}
User.h@interface User
@end
#import <Foundation/Foundation.h>
@property(nonatomic, strong) NSString *name;
@property(nonatomic) NSInteger age;
- (void)setAge:(NSInteger)age;- (NSInteger)age;
: NSObject
{ NSInteger _age;}
User.h@interface User
@end
#import <Foundation/Foundation.h>
@property(nonatomic, strong) NSString *name;
@property(nonatomic) NSInteger age;
- (void)deleteProfile;
- (void)setAge:(NSInteger)age;- (NSInteger)age;
: NSObject
{ NSInteger _age;}
User.h@interface User
@end
- (void)postCommentWithText:(NSString *)text;
- (void)postCommentWithTopic:(NSString *)topic andText:(NSString *)text;
#import <Foundation/Foundation.h>
@property(nonatomic, strong) NSString *name;
@property(nonatomic) NSInteger age;
- (void)deleteProfile;
- (void)setAge:(NSInteger)age;- (NSInteger)age;
: NSObject
{ NSInteger _age;}
User.m
User.m#import "User.h"
@implementation User
@end
User.m#import "User.h"
@implementation User
@end
@synthesize age = _age;@synthesize name = _name;
User.m#import "User.h"
@implementation User
@end
@synthesize age = _age;@synthesize name = _name;
- (void)setAge:(NSInteger)age{ _age = age; NSLog(@"Установили возраст %d", age);}
User.m#import "User.h"
@implementation User
@end
- (void)deleteProfile{ // удаляем из базы NSString *name = [self name]; NSLog(@"Пользователь %@ удален", name);}
- (void)postCommentWithText:(NSString *)text{ [self postCommentWithTopic:@"" andText:text];}
- (void)postCommentWithTopic:(NSString *)topic andText:(NSString *)text{ NSLog(@"Пользователь %@ (возраст: %d) с темой %@", self.name, self.age, topic);}
@synthesize age = _age;@synthesize name = _name;
- (void)setAge:(NSInteger)age{ _age = age; NSLog(@"Установили возраст %d", age);}
Admin.h
Admin.h#import "User.h"
@interface Admin : User
- (void)deleteComment:(NSInteger)key;
@end
Admin.h#import "User.h"
@interface Admin : User
- (void)deleteComment:(NSInteger)key;
@end
Admin.m
Admin.h#import "User.h"
@interface Admin : User
- (void)deleteComment:(NSInteger)key;
@end
Admin.m#import "Admin.h"
@implementation Admin
- (void)deleteComment:(NSInteger)key{ //удаляем из базы NSLog(@"Комментарий с ключом %d удален", key); // оставляем комментарий, об удалении [self postCommentWithTopic:@"От админа" andText:@"Удалил коммент за хамство"];}
@end
Инициализация объектов
Инициализация объектов
User *user = [[User alloc] init];
Инициализация объектов
User *user = [[User alloc] init];
user.age = 34;[user setName:@"UserName"];
Инициализация объектов
NSString *comment = @"БлаБлаБла";
[user postCommentWithText:comment]; [user deleteProfile];
User *user = [[User alloc] init];
user.age = 34;[user setName:@"UserName"];
Собственный инициализатор
Собственный инициализатор
- (id)initWithName:(NSString *)name{ self = [super init]; if (self) { self.name = name; } return self;}
Собственный инициализатор
- (id)initWithName:(NSString *)name{ self = [super init]; if (self) { self.name = name; } return self;}
- (id)init{ return [self initWithName:@"Имя по умолчанию"];}
Методы класса
Методы классаВ файле Admin.h:
Методы класса
+ (Admin *)createAdmin;
В файле Admin.h:
Методы класса
+ (Admin *)createAdmin;
В файле Admin.h:
В файле Admin.m:
Методы класса
+ (Admin *)createAdmin;
+ (Admin *)createAdmin{ Admin *admin = [[Admin alloc] initWithName:@"Админ Админович"]; admin.age = 34; return admin;}
В файле Admin.h:
В файле Admin.m:
Методы класса
+ (Admin *)createAdmin;
+ (Admin *)createAdmin{ Admin *admin = [[Admin alloc] initWithName:@"Админ Админович"]; admin.age = 34; return admin;}
В файле Admin.h:
В файле Admin.m:
Использование:
Методы класса
+ (Admin *)createAdmin;
+ (Admin *)createAdmin{ Admin *admin = [[Admin alloc] initWithName:@"Админ Админович"]; admin.age = 34; return admin;}
В файле Admin.h:
В файле Admin.m:
Использование:
Admin *admin = [Admin createAdmin]; [admin deleteComment:10];
Тип id
Селекторы
NSString *a = @"a";id b = a;if ([b respondsToSelector:@selector(isEqualToString:)]){@ BOOL e = [b isEqualToString:@"a"];}
SEL s = @selector(removeAllObjects);NSMutableArray *arr = ...;[arr performSelector:s];[arr makeObjectsPerformSelector:s]
Классы
NSString *a = @"a";id b = a;if ([b isKindOfClass:[NSString class]]){@ BOOL e = [b isEqualToString:@"a"];}
Протоколы
Протоколы@protocol SendMessageProtocol
- (void)sendMessage:(NSString *)message;
@end
Протоколы@protocol SendMessageProtocol
- (void)sendMessage:(NSString *)message;
@end
@interface User : NSObject<SendMessageProtocol>
@end
Протоколы@protocol SendMessageProtocol
- (void)sendMessage:(NSString *)message;
@end
@interface User : NSObject<SendMessageProtocol>
@end
@implementation User
- (void)sendMessage:(NSString *)message{ // send message}
@end
Протоколы@protocol SendMessageProtocol
- (void)sendMessage:(NSString *)message;
@end
@interface User : NSObject<SendMessageProtocol>
@end
@implementation User
- (void)sendMessage:(NSString *)message{ // send message}
@end
id<SendMessageProtocol> sender = [[User alloc] init];[sender sendMessage:@"message"];
Категории
Категории@interface NSString(User)
- (User *)userWithName;
@end
Категории@interface NSString(User)
- (User *)userWithName;
@end
@implementation NSString(User)
- (User *)userWithName{ User *result = [[User alloc] init]; result.name = self; return result;}
@end
Категории@interface NSString(User)
- (User *)userWithName;
@end
@implementation NSString(User)
- (User *)userWithName{ User *result = [[User alloc] init]; result.name = self; return result;}
@end
User *test = [@"Username" userWithName];
Память
retain/release ARC
retainCountNSMutableString *a = [[NSMutableString alloc] init];NSLog(@"%d", [a retainCount]);[a appendString:@"a"];[a retain];NSLog(@"%d", [a retainCount]);[a release];NSLog(@"%d", [a retainCount]);[a release];
1
2
1dealloc
retain setter
- (void)setName:(NSString *)name{ NSString *prev = _name; _name = name; [_name retain]; [prev release];}
- (void)dealloc{ [super dealloc]; [_name release];}
autorelease- (NSString *)fullName{ NSMutableString *s = [[NSMutableString alloc] init]; [s appendString:[self name]]; [s appendString:@" "]; [s appendString:[self secondName]]; return [s autorelease];}
- (void)main{ NSString *name = [self fullName]; NSLog(@"%@", name);}
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
... [pool drain];
retain/release• после init счетчик ссылок равен 1
• когда объекту изменяют внутреннее поле через retain-setter: retain новому значению, release старому
• когда в массив или словарь добавляют элемент - ему retain
• когда удаляют элемент - release ему
ARC
• автоматически генерится dealloc
• автоматический retain/release при присваивании полей
• автоматический retain и autorelease для возвращаемого значения из метода
• автоматический release для локальной переменной при завершении области видимости
retain release autorelease [super dealloc]
ARC
NSString *a = [[NSString alloc] init];NSLog(@"%@", a);
release
- (void)setName:(NSString *)name{ _name = name;} retain
release- (void)dealloc{ NSLog(@"dealloc");}
[super dealloc];release всех полей
Цикл ссылок
CarNSArray *_wheels
WheelCar *car
Car *car = [[[Car alloc] init] autorelease];Wheel *wheel = [[[Wheel alloc] init] autorelease];
[wheel setCar:car];[car addWheel:wheel]; retainCount = 2
после autorelease будет retainCount = 1
Модификаторы• strong
• weak
• unsafe_unretained
• copy@interface Car : NSObject
@property(strong, nonatomic) NSArray *wheels;
@end
@interface Wheel : NSObject
@property(weak, nonatomic) Car *car;
@end
Objective-C style guide• Локальные переменные: myLocalVariable
• Свойства: myProperty
• Классы: MyClass
• Методы: doSomethingWith:
• Внутренние переменные: • _myLocal
• myLocal_
• myLocal
Демонстрация
Вопросы на засыпку
Какой метод управления памятью используется в языке Си?
А в Objective-C?
Чем отличаются строки "string1" и @"string2"
Как сохранить число 5 в массив?
Как создать объект?
Что такое «strong» и «weak»?
Чем они отличаются?