Записки Фрилансера: Делимся опытом, часть 1

от автора

imageЗдравствуйте, дорогие читатели Хабра!

Я разрабатываю приложения под iOS и Mac OS. Уже около года занимаюсь фрилансом и, переходя от клиента к клиенту, начал замечать, что в задаче разбираюсь одиножды; а при появлении похожего заказа, просто использую уже разработанные ранее модули. В серии статей «Записки Фрилансера» я постараюсь осветить некоторые часто встречающиеся в заказах аспекты; напишу подобие шпаргалки, прочитав которую, вы сможете быстро и безболезненно внедрить новую технологию в свой проект. Мои заметки ни в коем случае не претендуют на глубокое понимание процессов, но описывают легкий способ закончить заказ в срок.

Содержание:

  1. Часть 1: Работа с Файлами; Шаблон Singleton; Работа с Аудио; Работа с Видео; In-App Purchases
  2. Часть 2: Собственные всплывающие окна (Popups); Как использовать Modal Segue в Navigation Controller; Core Graphics; Работа с UIWebView и ScrollView
  3. Часть 3: Жизнь без Autolayout; Splash Screen; Работа с ориентацией девайса в iOS 6+; Сдвиг содержимого UITextField
  4. Часть 4: Google Analytics; Push Notifications; PSPDFKit; Вход в приложение через Facebook; Рассказать друзьям — Facebook, Twitter, Email
  5. Часть 5: Core Data; UITableView и UICollectionView

Работа с Файлами

Многие начинающие iOS разработчики натыкаются на следующую проблему: приложение корректно работает в симуляторе, но отказывается работать или работает некорректно на реальном устройстве. Одна из возможных проблем состоит в том, что приложение активно использует файловые ресурсы, неперенесенные в папку документов приложения. Политика Apple такова: вы не можете менять файлы приложения. Единственное место, где можно развлечься — это папка документов. Читать вы можете отовсюду (в рамках своего приложения), а вот писать только в папке документов.
Значит, при первом запуске, нужно перенести все документы для записи в папку документов! Запросто! Начнем с создания файла Config.h, добавим следующую строчку в Your_App_Name-Prefix.pch (этот файл автоматически добавлен во все файлы вашего проекта):

#import "Config.h" 

Отлично! Теперь все, что есть в Config.h, есть и во всем проекте! Давайте заполним этот файл:

#define pathToApplicationDirectory [[NSBundle mainBundle] bundlePath] // Путь к папке приложения #define pathToDocuments [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject] // Путь к документам  #define pathToSettings [[pathToDocuments URLByAppendingPathComponent:@"settings.plist"] path] // Путь к файлу настроек #define pathToPopups [[NSBundle mainBundle] pathForResource:@"popups" ofType:@"plist"] // Путь к файлу со всплывающими окнами 

Все это делается исключительно для нашего с вами удобства в будущем (работать с файлами мы будем много и хорошо бы избавиться от магических строк).
Теперь можно приступить к копированию файлов в папку с документами. Файлы settings.plist и popups.plist мы будем часто изменять, так что пункт с копированием необходим. Добавим следующий код в наш application: didFinishLaunchingWithOptions:

// Я юзер, а не лузер, так что перемещу ресурсы к документам! [self placeResourcesToDocumentsDirectory:@{      @"settings" : @"plist",      @"popups" : @"plist"}]; 

И, конечно же, сам метод placeResourcesToDocumentsDirectory:

Жми меня!

/*!  Метод, копирующий файлы из словаря в папку с документами  /param Словарь с именами файлов   */ - (void)placeResourcesToDocumentsDirectory:(NSDictionary *)resources {     // Проверим один из файлов, вдруг скопировано уже     if (![[NSFileManager defaultManager] fileExistsAtPath:pathToSettings) {                  for (NSString *fileName in [resources allKeys]) {             NSString *extension = resources[fileName];                          NSURL *storeURL = [pathToDocuments URLByAppendingPathComponent:[NSString stringWithFormat:@"%@.%@", fileName, extension]];             NSURL *preloadURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:fileName ofType:extension]];             NSError *error = nil;             [[NSFileManager defaultManager] copyItemAtURL:preloadURL toURL:storeURL error:&error];         }     } } 

Вот и все! Как просто оказалось переместить файлы в нужную папку, не так ли? А получать доступ к файлу и работать с ним можно вот так:

NSMutableDictionary *settings = [NSMutableDictionary dictionaryWithContentsOfFile:pathToSettings]; settings[@"isThisAppCool"] = @YES; [settings writeToFile:pathToSettings atomically:YES]; 

Шаблон Singleton

Это скорее небольшой сниппет, который может облегчить вам работу с одиночками.
Singleton.h:

Жми меня!

<...> // Упростим доступ к синглтону #define coolSingleton [Singleton sharedSingleton]  @interface Singleton : NSObject + (Singleton *)sharedSingleton; <...> 

Singleton.m:

Жми меня!

<...> @implementation Singleton  static Singleton *sharedSingleton;  + (Singleton *)sharedSingleton {     if (sharedSingleton == nil) {         sharedSingleton = [[Singleton alloc] init];     }     return sharedSingleton; } <...> 

Здесь все просто. Во-первых, мы упростили одной дефиницией работу с синглтоном. Во-вторых, есть один статичный объект класса Singleton. В-третьих, по вызову метода класса sharedSingleton мы получим либо уже существующий объект, либо инициализируем новый. Всегда будет только один объект класса Singleton.

Работа с Аудио

Здесь нам придется поработать с классом AVAudioPlayer из фреймворка AVFoundation. Принцип действия прост: создаем объект класса AVAudioPlayer с именем определенного файла, подготавливаем его к воспроизведению и запускаем, когда нужно. Создадим простой синглтон, который и будет содержать все наши аудиоплееры. У нас будет два аудиоплеера: один для фоновой музыки, второй для воспроизведения звука нажатия кнопки.

Посмотрим на SimpleAudioPlayer.h:

Жми меня!

#import <Foundation/Foundation.h> #import <AVFoundation/AVFoundation.h>  #define audioPlayer [SimpleAudioPlayer sharedAudioPlayer]  @interface SimpleAudioPlayer : NSObject @property (nonatomic, retain) AVAudioPlayer *backgroundMusicPlayer; @property (nonatomic, retain) AVAudioPlayer *buttonSoundPlayer;  + (SimpleAudioPlayer *)sharedAudioPlayer;  @end 

И на SimpleAudioPlayer.m:

Жми меня!

#import "SimpleAudioPlayer.h"  @implementation SimpleAudioPlayer  static SimpleAudioPlayer *sharedAudioPlayer;  + (SimpleAudioPlayer *)sharedAudioPlayer {     if (sharedAudioPlayer == nil) {         sharedAudioPlayer = [[SimpleAudioPlayer alloc] init];     }     return sharedAudioPlayer; }  - (id)init {     self = [super init];     if (self) {         [self initAudioPlayers];     }     return self; }  /*!   Метод, инициализирующий аудиоплееры  */ - (void)initAudioPlayers {     NSURL *fileURL = [[NSURL alloc] initFileURLWithPath:pathToBackgroundAudio];     self.backgroundMusicPlayer = [[AVAudioPlayer alloc]                         initWithContentsOfURL:fileURL error:nil];     [self.backgroundMusicPlayer prepareToPlay];     self.backgroundMusicPlayer.numberOfLoops = -1;          fileURL = [[NSURL alloc] initFileURLWithPath:pathToButtonAudio];     self.buttonSoundPlayer = [[AVAudioPlayer alloc]                               initWithContentsOfURL:fileURL error:nil];     [self.buttonSoundPlayer prepareToPlay]; } 

Вот и все. Дефиниции путей к аудиофайлам можно прописать в Config.h. Стоит отметить, что мы указали отрицательное число для количества повторений фоновой музыки. Если вы установите отрицательное число у этого свойства — то аудиофайл будет повторяться бесконечно. То, что надо! Так же не стоит забывать о методе prepareToPlay — если подготовить все аудиоплееры, как только приложение запущено, то не будет маленькой задержки перед первым воспроизведением аудиофайла. А пользоваться нашим аудиоплеером можно вот так:

[audioPlayer.backgroundMusicPlayer play]; <...> [audioPlayer.backgroundMusicPlayer stop]; 

Работа с видео

Поработаем немного с фреймворком MediaPlayer. Фактически, следующий код можно добавить даже в метод viewDidAppear:

NSURL *url = [[NSURL alloc] initFileURLWithPath:pathToMovie]; MPMoviePlayerViewController *movieController = [[MPMoviePlayerViewController alloc] initWithContentURL:url]; [self presentMoviePlayerViewControllerAnimated:movieController]; [movieController.moviePlayer play]; 

Этот код просто показывает видеофайл по данному URL. В видеопроигрывателе от Apple уже есть все нужные кнопочки, чтобы видеопроигрыватель закрыть. Так что четыре строчки выше — минимальный набор символов для включения видео в ваше приложение.

In-App Purchases

Ну, и самое интересное на сегодня: фреймворк StoreKit! Правда, работать мы будем не напрямую с ним, но с MKStoreKit. Огромное спасибо MugunthKumar за великолепный фреймворк!

Все просто: отредактируйте файл MKStoreKitConfigs.plist под ваши нужды (там все интуитивно понятно) и используйте следующий код для проверки покупок:

if ([MKStoreManager isFeaturePurchased:@"me.identifier.coolapp.somesinglefeature"]) { // Юзер уже купил эту фишку! Нужно ее ему отдать! } if ([MKStoreManager isSubscriptionActive:@"me.identifier.coolapp.somesubscription"]) { // Вау! Да мы можем тянуть деньги ежемесячно, еженедельно, ежедневно! Но сегодня юзер уже заплатил, отдадим ему заслуженную плюшку } 

Для осуществления покупок используйте следующее:

[[MKStoreManager sharedManager] buyFeature:@"me.identifier.coolapp.somesinglefeature"                                  onComplete:^(NSString* purchasedFeature,                                               NSData* purchasedReceipt,                                               NSArray* availableDownloads) {      NSLog(@"Юзер купил: %@", purchasedFeature);  }                                onCancelled:^ {      NSLog(@"Юзер отказался покупать :( печально.");  }]; 

Заключение

Вот и все на сегодня. Эта часть была пилотной, в следующих статьях будем рассматривать примеры поинтереснее. Например, как создать такое всплывающее окно, чтобы наш клиент мог изменять его поведение прямо в .xib файлах, без вашего участия.

Обо всех ошибках и неточностях статьи прошу писать в мой хабрацентр.

P.S. Если Вы хотите сотрудничать со мной, то мой профиль есть на одной из крупных бирж фрилансеров.

Стоит ли продолжать серию статей «Записки Фрилансера»? Выразите свое мнение в комментариях.

ссылка на оригинал статьи http://habrahabr.ru/post/192062/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *