This does not require sending queues or operation queues.
NSURLSession, , AVAudioPlayer. , cancel, stop .
:
@class Song;
@protocol SongDelegate <NSObject>
- (void)song:(Song *)song didFinishPlayingSuccessfully:(BOOL)flag;
- (void)song:(Song *)song didFinishDownloadWithError:(NSError *)error;
@end
@interface Song: NSObject <AVAudioPlayerDelegate>
@property (nonatomic, strong) NSURL *url;
@property (nonatomic, weak) NSURLSessionTask *downloadTask;
@property (nonatomic, strong) NSURL *localURL;
@property (nonatomic, strong) AVAudioPlayer *player;
@property (nonatomic, weak) id<SongDelegate> delegate;
@end
@implementation Song
+ (instancetype)songWithURL:(NSURL *)url delegate:(id<SongDelegate>)delegate {
Song *song = [[Song alloc] init];
song.url = url;
song.delegate = delegate;
return song;
}
- (void)downloadAndPlay {
self.downloadTask = [[NSURLSession sharedSession] downloadTaskWithURL:self.url completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate song:self didFinishDownloadWithError:error];
});
NSURL *documentsURL = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:false error:&error];
NSAssert(documentsURL, @"URLForDirectory failed: %@", error);
NSURL *fileURL = [documentsURL URLByAppendingPathComponent:self.url.lastPathComponent];
NSError *moveError;
BOOL success = [[NSFileManager defaultManager] moveItemAtURL:location toURL:fileURL error:&moveError];
NSAssert(success, moveError.localizedDescription);
dispatch_async(dispatch_get_main_queue(), ^{
self.localURL = fileURL;
NSError *playError;
self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:&playError];
self.player.delegate = self;
[self.player play];
NSAssert(playError == nil, playError.localizedDescription);
});
}];
[self.downloadTask resume];
}
- (void)cancel {
[self.downloadTask cancel];
[self.player stop];
}
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag {
self.player = nil;
[self.delegate song:self didFinishPlayingSuccessfully:flag];
}
@end
, , downloadAndPlay , , . cancel , , , .
:
@interface ViewController () <SongDelegate>
@property (nonatomic, strong) Song *song;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.song = [Song songWithURL:[NSURL URLWithString:@"http://dl.last.fm/static/1464677535/131211148/70b3b5a9d048c7939d5bb9ec87a2c5d58d6ee528828f5c6a5b7b1eddd69f4553/Death+Grips+-+Get+Got.mp3"] delegate:self];
}
- (IBAction)didTapPlayButton:(id)sender {
[self.song downloadAndPlay];
}
- (IBAction)didTapStopButton:(id)sender {
[self.song cancel];
}
- (void)song:(Song *)song didFinishPlayingSuccessfully:(BOOL)flag {
NSLog(@"did finish playing %@", flag ? @"successfully" : @"unsuccessfully");
}
- (void)song:(Song *)song didFinishDownloadWithError:(NSError *)error {
NSLog(@"did finish download with error %@", error.localizedDescription);
}
@end
, , ( NSAssert, - , , , , Song, , 2 1 ..), , , , . , , .
, NSURLSession -https- - , , info.plist ( , " " - " " ), - :
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>dl.last.fm</key>
<dict>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSTemporaryExceptionMinimumTLSVersion</key>
<string>TLSv1.1</string>
</dict>
</dict>
</dict>