Горячие клавиши xCode

control+cmd+? (для ? может понадобиться shift) или option+click — всплывающая подсказка
control+option+cmd+/ или option+double click — открыть документацию по интересующему тексту

Остальное можно найти здесь:

http://iphonedev.tv/blog/2014/9/15/14-xcode-time-saving-shortcuts-memorize-and-improve-your-productivity

Простое создание одновременных и последовательных анимаций

Когда используете animateWithDuration, то анимации постоянно конфликтуют между собой. А для одновременных анимаций проще всего делать «nested animations» (но при этом блоки animateWithDuration, вложены друг в друга).

Проблему решает библиотека RZViewActions:

https://github.com/Raizlabs/RZViewActions

Базируется на animateWithDuration, но при этом есть 3 основных объекта:
1)анимация;
2)группа (для параллельных анимаций);
3)последовательность (для последовательных анимаций).

Группа и последовательность инициализируются через массив объектов-анимаций и при этом унаследованы от класса анимации. Т.е. можно из объектов анимации построить большое сложное дерево. Получается что-то вроде ReactiveCocoa (но не такой сложный) и PromiseKit (но без проблем поддерживает iOS 7):
- анимации не обязательно вкладывать друг в друга;
- теоретически можно связать анимации между собой анимации через внешние переменные.

В дополнение к этому, с библиотекой поставляется пример. Если в этом примере разрешить многократно запускать анимацию, то можно заметить, что для одновременности достаточно просто создать один объект анимации и запустить его, только при этом нужно следить, чтобы запущено было в том же цикле NSRunLoop

Директивы компилятора Objective-C

Статья частично устарела, но может дать представление о различных директивах компилятора (начинающиеся со знака @):

http://itw66.ru/blog/obj_c/585.html

Что изменилось:
- @«string» называется литералом и с тех пор к нему добавлись массивы, словари, NSNumber и т.п.;
- категория не может добавлять переменных экземпляра? Можно добавлять свойства, которые будут работать как переменные;
- что-то запутанное про synthesize и dynamic — из статьи не ясна разница между ними. К тому же сейчас использовать synthesize необязательно — будут только особенности доступа к свойству/переменной;
- обработка исключений есть, но в полноценных проектах не встречал. Objective-C — это не Java, где вместо объектов-ошибок используют исключения.

Как определить, поддерживает ли устройство на iOS эффект blur (размытие)?

Вариант 1. Требуется определить поддерживает ли устройство blur программно.
Решение:

http://stackoverflow.com/questions/19412094/how-can-i-detect-if-an-ios-device-supports-the-blur-effect

Код:

@interface UIDevice (Additions)

@property (readonly) NSString *platform;
@property (readonly) BOOL canBlur;

@end


@implementation UIDevice (Additions)

- (NSString *)platform {
    int mib[] = { CTL_HW, HW_MACHINE };
    size_t len = 0;
    sysctl(mib, 2, NULL, &len, NULL, 0);
    char *machine = malloc(len);
    sysctl(mib, 2, machine, &len, NULL, 0);
    NSString *platform = [NSString stringWithCString:machine encoding:NSASCIIStringEncoding];
    free(machine);

    return platform;
}

- (BOOL)canBlur {
    if(NSStringFromClass([UIVisualEffectView class]) && UIDevice.currentDevice.systemVersion.floatValue >= 8.0 && !UIAccessibilityIsReduceTransparencyEnabled()) {
        NSString *platform = self.platform;
        CGFloat deviceVersion = [[[platform stringByReplacingOccurrencesOfString:@"[^0-9,.]" withString:@"" options:NSRegularExpressionSearch range:NSMakeRange(0, platform.length)] stringByReplacingOccurrencesOfString:@"," withString:@"."] floatValue];

        if([platform isEqualToString:@"i386"] || [platform isEqualToString:@"x86_64"]) {
            return YES;
        } else if([platform rangeOfString:@"iPhone"].location != NSNotFound) {
            return (deviceVersion >= 4.1);
        } else if([platform rangeOfString:@"iPod"].location != NSNotFound) {
            return (deviceVersion >= 5.1);
        } else if([platform rangeOfString:@"iPad"].location != NSNotFound) {
            return (deviceVersion >= 3.4);
        }
    }

    return NO;
}

Важно помнить:
- включается/отключается только через системные настройки;
- blur (размытие) и прозрачность включается/отключается одновременно;
- в iOS 7 можно отключить эффект, но только в iOS 8 можно определить, отключен ли он. В самом приложении Apple только предлагает (но не настаивает) следить за прозрачностью, т.е. например можно сделать полупрозрачный элемент, когда в системе прозрачность отключена;
- поддержка blur на уровне ОС зависит не только от версии iOS, но и от типа устройства. Подробный список ниже.

Вариант 2. Определить поддержку конкретного устройства.
Первый способ хорош для компьютера, но не очень нагляден для человека. Здесь можно увидеть, какой строкой обозначается конкретная модель устройства в приложении:

http://stackoverflow.com/questions/448162/determine-device-iphone-ipod-touch-with-iphone-sdk

Дочерний UIView блокирует срабатывание события TouchesBegan для родительского UIView

Суть проблемы — событие TouchesBegan срабатывает непосредственно на view, которого касается пользователь. У superview по умолчанию событие не срабатывает.
Ссылка на решение проблемы:

http://stackoverflow.com/questions/12811848/subview-blocking-parent-view-touchesbegan

Решение — в дочернем UIView нужно прописать следующий код:

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
   [super touchesBegan:touches withEvent:event];
   [self.nextResponder touchesBegan:touches withEvent:event];
}

Это передаст обработку событием «дальше».

Почему нельзя использовать retainCount

Источники:

http://whentouseretaincount.com

http://www.friday.com/bbum/2011/12/18/retaincount-is-useless/

Более того — для объектов-констант xCode возвращает разные значения, например, для [NSNumber numberWithInt:1] и @»Foo».

Краткое содержание:
1)retainCount может изменяться при пропускании объекта через какое-либо системное API
2)возвращаемое значение может зависеть от специфики объектов
3)retainCount не учитывает autoreleased объекты
4)autorelease связано с потоками, а retainCount — глобальная величина
5)retainCount может никогда не вернуть ноль
6)синглтоны (в том числе системные)
7)некоторые классы могут манипулировать retainCount самостоятельно, т.е.вам нельзя использовать method-swizzling
8)команды retain/release потокобезопасны, а возвращаемое retainCount значение может оказаться неактуальным

iOS. Разница между singleton для ARC и не-ARC

Источник:

https://github.com/IgorFedorchuk/objective-c-style-guide

Исходный код

#if __has_feature(objc_arc) // ARC Version

#define SYNTHESIZE_SINGLETON_FOR_CLASS(classname)	\
\
+ (classname *)sharedInstance\
{\
    static classname *shared##classname = nil;\
    static dispatch_once_t onceToken;\
    dispatch_once(&onceToken, ^{\
        shared##classname = [[self alloc] init];\
    });\
    return shared##classname;\
}

#else // Non-ARC Version

#define SYNTHESIZE_SINGLETON_FOR_CLASS(classname) \
static classname *shared##classname = nil; \
+ (classname *)sharedInstance \
{ \
    @synchronized(self) \
    { \
        if (shared##classname == nil) \
        { \
            shared##classname = [[self alloc] init]; \
        } \
    } \
    return shared##classname; \
} \
\
+ (id)allocWithZone:(NSZone *)zone \
{ \
@synchronized(self) \
{ \
if (shared##classname == nil) \
{ \
shared##classname = [super allocWithZone:zone]; \
return shared##classname; \
} \
} \
return nil; \
} \
- (id)copyWithZone:(NSZone *)zone \
{ \
return self; \
} \
- (id)retain \
{ \
return self; \
} \
- (NSUInteger)retainCount \
{ \
return NSUIntegerMax; \
} \
- (oneway void)release \
{ \
} \
- (id)autorelease \
{ \
return self; \
}

#endif

Разница:
1)dispatch_once
2)статическая переменная объявлена внутри функции/вне ее (возможно, не имеет значения)

Используем OCMock не по назначению.

OCMock — фреймворк, предназначенный для тестирования приложений:

http://ocmock.org/

Кроме unit-тестов его можно использовать не по назначению, как альтернативу method swizzling.
Можно:
- подменить метод существующего объекта;
- создать объект некоторого класса и подменить в нем метод.
Нельзя заменить метод в классе так, чтобы класс создавал объекты с измененным методом.

Core Data + MagicalRecord. Пример работы с несколькими контекстами

Сначала инициализируем MagicalRecord. Создаем дочерний контекст и записываем в него что-нибудь, сохраняем в БД (после этого изменяется и родительский контекст).
Читаем из главного контекста, проверяем, что внесенные в дочерний контекст изменения появились в главном контексте.
Удаляем записи из дочернего контекста и применяем изменения без сохранения в БД. Эти изменения должны проявиться и в родительском контексте, но если остановить приложение на этом месте и перезапустить, то изменения исчезнут.
Далее пробуем сохранить изменения и в родительском контексте и в БД. Если после этого приложение перезапустить, то внесенные изменения останутся.

    [MagicalRecord setupCoreDataStack];
    NSManagedObjectContext *parentContext = [NSManagedObjectContext MR_defaultContext];

        NSManagedObjectContext *moc = [NSManagedObjectContext MR_contextWithParent:parentContext];
        BCExchange *exc = [BCExchange MR_createInContext:moc];
        exc.identifier = @"111";
        exc.name = @"ddddd";
        [moc MR_saveToPersistentStoreAndWait];
    
    {
        NSArray *arr = [BCExchange MR_findAllInContext:parentContext];
        NSLog(@"%d", arr.count);
    }
    
    [BCExchange MR_truncateAllInContext:moc];
    [moc MR_saveOnlySelfAndWait];
    {
        NSArray *arr = [BCExchange MR_findAllInContext:parentContext];
        NSLog(@"%d", arr.count);
    }
    
    [moc MR_saveToPersistentStoreAndWait];
    {
        NSArray *arr = [BCExchange MR_findAllInContext:parentContext];
        NSLog(@"%d", arr.count);
    }

xCode. Сбросить параметры target

В проекте xCode при сборке проекта берутся параметры для target. Если такие не заданы, то берутся из настроек проекта, общих для всех targets. Соответственно любое изменеие опции в target перекроет общие настройки.

Для сброса настройки в исходное положение нужно выбрать необходимую строку и нажать delete.