
Hello, dear readers Habr!
I develop applications for iOS and Mac OS. For about a year I have been involved in freelancing and, moving from client to client, I began to notice that I understand the task once; and when a similar order appears, I simply use the modules already developed earlier. In the iOS Developer Notes series of articles, I will try to highlight some aspects that are often found in orders; I will write something like a cheat sheet, after reading which, you can quickly and painlessly introduce a new technology into your project. My notes do not in any way pretend to a deep understanding of the processes, but they describe an easy way to complete an order on time.
Content:
')
- Part 1: Working with Files; Template Singleton; Work with Audio; Work with Video; In-app purchases
- Part 2: Own popups (Popups); How to use Modal Segue in the Navigation Controller; Core Graphics; Working with UIWebView and ScrollView
- Part 3: Life without Autolayout; Splash Screen; Work with device orientation in iOS 6+; Shifting the contents of a UITextField
- Part 4: Google Analytics; Push Notifications; PSPDFKit; Login to the app via Facebook; Tell friends - Facebook, Twitter, Email
- Part 5: Core Data; UITableView and UICollectionView
Work with Files
Many novice iOS developers stumble on the following problem: the application works correctly in the simulator, but refuses to work or does not work correctly on a real device. One of the possible problems is that the application actively uses file resources that are not transferred to the application documents folder. Apple’s policy is: you cannot change application files. The only place where you can have fun is the document folder. You can read from anywhere (within your application), but you can only write in the document folder.
So, when you first start, you need to transfer all documents to write to the documents folder! Easily! Start by creating the
Config.h file, add the following line to
Your_App_Name-Prefix.pch (this file is automatically added to all files of your project):
#import "Config.h"
Fine! Now all that is in
Config.h is in the whole project! Let's fill this file:
#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"] //
All this is done exclusively for our convenience with you in the future (we will work a lot with the files and it would be good to get rid of the magic lines).
Now you can start copying files to the folder with documents. We will often change the
settings.plist and
popups.plist files, so the copy item is necessary. Add the following code to our
application: didFinishLaunchingWithOptions:
And, of course, the
placeResourcesToDocumentsDirectory method
itself:Push me! - (void)placeResourcesToDocumentsDirectory:(NSDictionary *)resources {
That's all! How easy it was to move files to the right folder, right? And you can access and work with the file like this:
NSMutableDictionary *settings = [NSMutableDictionary dictionaryWithContentsOfFile:pathToSettings]; settings[@"isThisAppCool"] = @YES; [settings writeToFile:pathToSettings atomically:YES];
Singleton pattern
It is rather a small snippet that can make it easier for you to work with singles.
Singleton.h :
Singleton.m :
Push me! <...> @implementation Singleton + (Singleton *)sharedSingleton { static Singleton *sharedSingleton = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ sharedSingleton = [[self alloc] init]; }); return sharedSingleton; } <...>
Everything is simple here. First of all, we have simplified the work with the singleton with one definition. Secondly, there is one static object of class Singleton. Thirdly, by calling the
sharedSingleton class
method, we will get either an existing object or initialize a new one. There will always be only one singleton object. Fourthly, our singleton is thread-safe (thanks to
danilNik and
AndrewShmig for the tip!).
Work with Audio
Here we have to work with the AVAudioPlayer class from the AVFoundation framework. The principle of operation is simple: create an object of the AVAudioPlayer class with the name of a specific file, prepare it for playback and launch it when necessary. Let's create a simple singleton, which will contain all our audio players. We will have two audio players: one for background music, the second for playing a button click sound.
Look at
SimpleAudioPlayer.h :
Push me! #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
And on
SimpleAudioPlayer.m :
Push me! #import "SimpleAudioPlayer.h" @implementation SimpleAudioPlayer static SimpleAudioPlayer *sharedAudioPlayer; + (SimpleAudioPlayer *)sharedAudioPlayer { static SimpleAudioPlayer *sharedAudioPlayer = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ sharedAudioPlayer = [[self 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]; }
That's all. Definitions of paths to audio files can be
specified in
Config.h . It is worth noting that we indicated a negative number for the number of repetitions of background music. If you set a negative number for this property, then the audio file will repeat indefinitely. What you need! Also, do not forget about the
prepareToPlay method - if you prepare all audio players as soon as the application is launched, there will not be a small delay before the first playback of the audio file. And you can use our audio player like this:
[audioPlayer.backgroundMusicPlayer play]; <...> [audioPlayer.backgroundMusicPlayer stop];
Work with video
Let's work a bit with the MediaPlayer framework. In fact, the following code can be added even to the
viewDidAppear method:
NSURL *url = [[NSURL alloc] initFileURLWithPath:pathToMovie]; MPMoviePlayerViewController *movieController = [[MPMoviePlayerViewController alloc] initWithContentURL:url]; [self presentMoviePlayerViewControllerAnimated:movieController]; [movieController.moviePlayer play];
This code simply shows the video at the given URL. Apple's video player already has all the necessary buttons to close the video player. So the four lines above are the minimum set of characters to include video in your application.
In-app purchases
Well, and the most interesting for today: StoreKit framework! True, we will work not directly with him, but with
MKStoreKit . Thank you so much MugunthKumar for the great framework!
It's simple: edit the
MKStoreKitConfigs.plist file to
suit your needs (everything is intuitively clear) and use the following code to check purchases:
if ([MKStoreManager isFeaturePurchased:@"me.identifier.coolapp.somesinglefeature"]) {
To make purchases, use the following:
[[MKStoreManager sharedManager] buyFeature:@"me.identifier.coolapp.somesinglefeature" onComplete:^(NSString* purchasedFeature, NSData* purchasedReceipt, NSArray* availableDownloads) { NSLog(@" : %@", purchasedFeature); } onCancelled:^ { NSLog(@" :( ."); }];
Conclusion
That's all for today. This part was a pilot, in the following articles we will consider examples more interesting. For example, how to create such a pop-up window so that our client can change his behavior directly in .xib files, without your participation.
I ask to write about all errors and inaccuracies of the article in
my habracenter .
PS If you want to cooperate with me, then my profile is on one of the
major exchanges of freelancers .
Should I continue the series of articles "Notes iOS developer?" Express your opinion in the comments.