Разработка приложений для iOS




          Лекция 1
   Objective-C



                            Глеб Тарасов
Мобильная разработка, что
      изменилось?
Особенности
• Высокие ожидания пользователей
• Другие паттерны использования
• Маленький экран
• Слабый процессор, мало памяти
• Медленный интернет
• Управление жестами
Почему 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

1986 — Objective-C. «Object-Oriented Programming, An
Evolutionary Approach» (Brad Cox).

1988 — NeXT лицензирует Objective-C

1996 — Apple покупает NeXT. Objective-C — основной
язык для Mac OS.

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 = malloc(sizeof(int) * 10);
    int a = 10;
}                   free(a);
{
    int a = 20;
}
Теперь немного ООП




http://ru.wikipedia.org/wiki/Объектно-ориентированное_программирование
Класс - описание внутреннего состояния + методов
изменения этого состояния

Объект - экземпляр класса

Поля - состояние объекта

Методы - изменение состояния объекта
Класс «Работник»
 Поля:
- имя (строка)
- возраст (целое)
- пол (м/ж)
- время_поступления_на_работу (дата)
- время_увольнения (дата)
- подчиненные (массив работников)
 Методы:
- уволить()
- добавить подчиненного(работник)
Наследование
Класс «Руководитель» (наследуется от
«Работник»)
   Поля:
 - подчиненные (массив работников)

  Методы:
 - добавить подчиненного(работник)
Objective-C
Синтаксис
NSString *a = [[NSString alloc] init];

NSString *b = [a copy];

NSString *c = @"string";

[b stringByReplacingOccurrencesOfString:@" " withString:@""];


[c stringByPaddingToLength:20
                withString:@" "
           startingAtIndex:0];
nil
• аналог null из других языков
• можно вызывать любой метод, не будет
  исключения
• если метод возвращает объект - вернется nil
• если метод возвращает число - вернется 0
• если метод возвращает структуру - результат не
  определен
nil
NSString *a = nil;
int length = [a length]; // 0
NSString *m = [a mutableCopy]; // nil
NSRange 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
             Неупорядоченная коллекция.
             Быстрая проверка на contains

NSSet *s = [NSSet setWithObjects:@"a", @"b", @"c", nil];
BOOL c = [s containsObject:@"b"];

NSMutableSet *m = [s mutableCopy];
[m addObject:@"d"];
[m removeObject:@"a"];
Перечисление (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




                          User.h
@end
Собственные классы
@interface User : NSObject




                             User.h
@end
Собственные классы
@interface User : NSObject
{
       NSString *_name;
}
                             User.h
@end
Собственные классы
@interface User : NSObject
{
       NSString *_name;
}
- (void)setName:(NSString *)name;   User.h
- (NSString *)name;

@end
Собственные классы
@interface User : NSObject
{
       NSString *_name;
}
- (void)setName:(NSString *)name;   User.h
- (NSString *)name;

@end




                                    User.m
Собственные классы
@interface User : NSObject
{
       NSString *_name;
}
- (void)setName:(NSString *)name;   User.h
- (NSString *)name;

@end


@implementation User



                                    User.m



@end
Собственные классы
@interface User : NSObject
{
       NSString *_name;
}
- (void)setName:(NSString *)name;   User.h
- (NSString *)name;

@end


@implementation User
- (void)setName:(NSString *)name
{

}
    _name = name;
                                    User.m
- (NSString *)name
{
    return _name;
}
@end
User.h
User.h
#import <Foundation/Foundation.h>
User.h
#import <Foundation/Foundation.h>

@interface User




@end
User.h
#import <Foundation/Foundation.h>

@interface User : NSObject




@end
User.h
#import <Foundation/Foundation.h>

@interface User : NSObject
{
       NSInteger _age;
}




@end
User.h
#import <Foundation/Foundation.h>

@interface User : NSObject
{
       NSInteger _age;
}
@property(nonatomic, strong) NSString *name;

@property(nonatomic) NSInteger age;




@end
User.h
#import <Foundation/Foundation.h>

@interface User : NSObject
{
       NSInteger _age;
}
@property(nonatomic, strong) NSString *name;

@property(nonatomic) NSInteger age;
- (void)setAge:(NSInteger)age;
- (NSInteger)age;




@end
User.h
#import <Foundation/Foundation.h>

@interface User : NSObject
{
       NSInteger _age;
}
@property(nonatomic, strong) NSString *name;

@property(nonatomic) NSInteger age;
- (void)setAge:(NSInteger)age;
- (NSInteger)age;

- (void)deleteProfile;




@end
User.h
#import <Foundation/Foundation.h>

@interface User : NSObject
{
       NSInteger _age;
}
@property(nonatomic, strong) NSString *name;

@property(nonatomic) NSInteger age;
- (void)setAge:(NSInteger)age;
- (NSInteger)age;

- (void)deleteProfile;

- (void)postCommentWithText:(NSString *)text;

- (void)postCommentWithTopic:(NSString *)topic andText:(NSString *)text;


@end
User.m
#import "User.h"

@implementation User
                       User.m




@end
#import "User.h"

@implementation User
                            User.m
@synthesize age = _age;
@synthesize name = _name;




@end
#import "User.h"

@implementation User
                            User.m
@synthesize age = _age;
@synthesize name = _name;

- (void)setAge:(NSInteger)age
{
    _age = age;
    NSLog(@"Установили возраст %d", age);
}




@end
#import "User.h"

@implementation User
                            User.m
@synthesize age = _age;
@synthesize name = _name;

- (void)setAge:(NSInteger)age
{
    _age = age;
    NSLog(@"Установили возраст %d", age);
}

- (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);
}

@end
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:@"Удалил коммент за хамство"];
}
Инициализация объектов
Инициализация объектов
User *user = [[User alloc] init];
Инициализация объектов
User *user = [[User alloc] init];
user.age = 34;
[user setName:@"UserName"];
Инициализация объектов
User *user = [[User alloc] init];
user.age = 34;
[user setName:@"UserName"];


NSString *comment = @"БлаБлаБла";

[user postCommentWithText:comment];

[user deleteProfile];
Собственный инициализатор
Собственный инициализатор
- (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.h:
+ (Admin *)createAdmin;
Методы класса
В файле Admin.h:
+ (Admin *)createAdmin;

В файле Admin.m:
Методы класса
В файле Admin.h:
+ (Admin *)createAdmin;

В файле Admin.m:
+ (Admin *)createAdmin
{
    Admin *admin = [[Admin alloc] initWithName:@"Админ Админович"];
    admin.age = 34;
    return admin;
}
Методы класса
В файле Admin.h:
+ (Admin *)createAdmin;

В файле Admin.m:
+ (Admin *)createAdmin
{
    Admin *admin = [[Admin alloc] initWithName:@"Админ Админович"];
    admin.age = 34;
    return admin;
}


Использование:
Методы класса
 В файле Admin.h:
 + (Admin *)createAdmin;

 В файле Admin.m:
+ (Admin *)createAdmin
{
    Admin *admin = [[Admin alloc] initWithName:@"Админ Админович"];
    admin.age = 34;
    return admin;
}


Использование:
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
retainCount
NSMutableString *a = [[NSMutableString alloc] init];
NSLog(@"%d", [a retainCount]);
[a appendString:@"a"];
[a retain];
NSLog(@"%d", [a retainCount]);            1
[a release];
NSLog(@"%d", [a retainCount]);
[a release];
                                          2
                                         1
                        dealloc
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
           retain    release autorelease
                    [super dealloc]

• автоматически генерится dealloc
• автоматический retain/release при присваивании
  полей
• автоматический retain и autorelease для
  возвращаемого значения из метода
• автоматический release для локальной
  переменной при завершении области видимости
ARC
NSString *a = [[NSString alloc] init];
NSLog(@"%@", a);
                          release
- (void)setName:(NSString *)name
{                                     [super dealloc];
    _name = name;
}                                     release всех полей
                       retain
          release               - (void)dealloc
                                {
                                    NSLog(@"dealloc");
                                }
Цикл ссылок
       Car                      Wheel
       NSArray *_wheels        Car *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»?

   Чем они отличаются?
Всё!

       Глеб Тарасов
       gleb34@gmail.com
       twitter.com/pilot34

Школа-студия разработки приложений для iOS. Лекция 1. Objective-C