1 简单的音乐播放器
1.1 问题
本案例结合之前所学的网络和数据解析等知识完成一个网络音乐播放器,如图-1所示:
图-1
1.2 方案
首先创建一个SingleViewApplication应用,在Storyboard文件中搭建音乐播放器界面,该应用有三个场景组成,第一个场景用于搜索,第二场景显示歌曲列表,第三个场景是播放歌曲界面,有一个播放进度条。这三个场景由一个导航视图控制器管理,如图-2所示:
图-2
本案例使用一个百度的音乐开放接口http://mp3.baidu.com,首先创建一个模型类TRMusicInfo存放音乐的相关信息。
其次将网络请求和解析的代码封装在两个类中TRWebUtils和TRParser。TRWebUtils类中有两个方法,一个是requestMusicsByWord:andCallBack:,该方法根据用户输入的歌手姓名获取到网络请求的路径,然后采用NSURLConnection类发送异步请求,返回的数据是Json格式的,然后采用NSJSONSerialization类进行Json解析,得到音乐的相关信息。
TRWebUtils类中的另一个方法requestMusicDetailByMusic:andCallBack,该方法是通过音乐信息中的音乐ID发送网络请求,然后通过数据解析获取到音乐的下载的地址和歌词地址。对应的在TRParser类有两个解析数据的方法parseMusicInfoByArray:和parseMusicDetailByDic:andMusic:。
然后完成音乐列表视图控制器TRMusicListViewController的代码,该视图控制器继承至UITableViewController,有一个NSMutableArray类型的属性musics,用于存放需要展示的音乐信息。在viewDidLoad方法中通过TRWebUtils类调用requestMusicsByWord:andCallBack:方法,根据用户输入的歌手姓名发送网络请求,解析歌曲数据得到属性self.music数据,刷新界面。
由于表视图的每个Cell需要展示歌曲的信息,所以这里需要自定义一个Cell,因此创建一个TRMusicCell类,继承至UITableViewCell类,需要显示专辑封面,歌曲名、歌手名以及专辑名,如图-3所示:
图-3
然后实现音乐播放视图控制器TRPlayViewController的代码,该视图控制器有一个TRMusicInfo类型的公开属性music,用于记录用户从上一个界面选择的音乐信息。
该视图控制器还有如下几个私有属性:
AVAudioPlayer类型的player,用于播放音乐;
NSURLConnection类型的conn,用于发送下载请求;
NSMutableData类型的allData,用于存放下载的音乐数据;
NSUInteger类型的fileLength,用于记录下载音乐的大小;
在TRPlayViewController的viewDidLoad方法中通过TRWebUtils类调用requestMusicDetailByMusic:andCallBack:方法,根据音乐信息获取到音乐的下载地址和歌词地址,然后通过音乐下载地址发送下载请求,将发送下载请求的代码封装在downloadMusic方法中。
接下来实现NSURLConnectionDelegate的协议方法,在connection:didReceiveResponse:方法中解析头文件,获取到文件的大小并初始化self.allData属性。
在connection:didReceiveData:方法中将下载到的音乐数据保存在self.allData中,并且创建音乐播放器并播放歌曲,实现边下载边播放的功能。
在connectionDidFinishLoading:方法中将音乐的数据存入本地。
最后开启一个计时器,更新进度条的显示,即音乐的播放进度。
1.3 步骤
实现此案例需要按照如下步骤进行。
步骤一:创建模型类
首先创建一个SingleViewApplication应用,在Storyboard文件中搭建音乐播放器界面,该应用有三个场景组成,第一个场景用于搜索,第二场景显示歌曲列表,第三个场景是播放歌曲界面,有一个播放进度条。
本案例使用一个百度的音乐开放接口http://mp3.baidu.com,首先创建一个模型类TRMusicInfo存放音乐的相关信息,代码如下所示:
- @interface TRMusicInfo : NSObject
- @property (nonatomic, copy)NSString *name;
- @property (nonatomic, copy)NSString *singerName;
- @property (nonatomic, copy)NSString *albumName;
- @property (nonatomic, copy)NSString *songID;
- @property (nonatomic, copy)NSString *albumImagePath;
- @property (nonatomic, copy)NSString *musicPath;
- @property (nonatomic, copy)NSString *lrcPath;
- @end
其次将网络请求和解析的代码封装在两个类中TRWebUtils和TRParser。TRWebUtils类中有两个方法,一个是requestMusicsByWord:andCallBack:,该方法根据用户输入的歌手姓名获取到网络请求的路径,然后采用NSURLConnection类发送异步请求,返回的数据是Json格式的,然后采用NSJSONSerialization类进行Json解析,得到音乐的相关信息,代码如下所示:
- + (void)requestMusicsByWord:(NSString *)word andCallBack:(MyCallback)callback{
- NSString *path = [NSString stringWithFormat:@"http://mp3.baidu.com/dev/api/?tn=getinfo&ct=0&word=%@&ie=utf-8&format=json",word];
- path = [path stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
- NSURL *url = [NSURL URLWithString:path];
- NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
- [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
- NSArray *arr = [NSJSONSerialization JSONObjectWithData:data options:0 error:Nil];
- if (arr.count==0) {
- [TRWebUtils requestMusicsByWord:word andCallBack:callback];
- }
- NSMutableArray *musics = [TRParser parseMusicInfoByArray:arr];
- callback(musics);
- }];
- }
TRWebUtils类中的另一个方法requestMusicDetailByMusic:andCallBack,该方法是通过音乐信息中的音乐ID发送网络请求,然后通过数据解析获取到音乐的下载的地址和歌词地址,代码如下所示:
- + (void)requestMusicDetailByMusic:(TRMusicInfo *)music andCallBack:(MyCallback)callback{
- NSString *path = [NSString stringWithFormat:@"http://ting.baidu.com/data/music/links?songIds=%@",music.songID];
- NSLog(@"%@",path);
- NSURL *url = [NSURL URLWithString:path];
- NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
- [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
- NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:data options:0 error:Nil];
- [TRParser parseMusicDetailByDic:dic andMusic:music];
- callback(music);
- }];
- }
对应的在TRParser类有两个解析数据的方法parseMusicInfoByArray:和parseMusicDetailByDic:andMusic:,代码如下所示:
- +(NSMutableArray *)parseMusicInfoByArray:(NSArray *)arr{
- NSMutableArray *musics = [NSMutableArray array];
- for (NSDictionary *musicDic in arr) {
- TRMusicInfo *mi = [[TRMusicInfo alloc]init];
- mi.name = [musicDic objectForKey:@"song"];
- mi.singerName = [musicDic objectForKey:@"singer"];
- mi.albumName = [musicDic objectForKey:@"album"];
- mi.songID = [musicDic objectForKey:@"song_id"];
- mi.albumImagePath = [musicDic objectForKey:@"albumPicSmall"];
- [musics addObject:mi];
- }
- return musics;
- }
- +(void)parseMusicDetailByDic:(NSDictionary *)dic andMusic:(TRMusicInfo *)music{
- NSDictionary *dataDic = [dic objectForKey:@"data"];
- NSArray *songListArr = [dataDic objectForKey:@"songList"];
- NSDictionary *musicDic = [songListArr lastObject];
- NSString *musicPath = [musicDic objectForKey:@"showLink"];
- music.musicPath = musicPath;
- music.lrcPath = [NSString stringWithFormat:@"http://ting.baidu.com%@",[musicDic objectForKey:@"lrcLink"]];
- }
步骤二:实现TRMusicListViewController展示音乐列表功能
音乐列表视图控制器TRMusicListViewController继承至UITableViewController,它有一个NSMutableArray类型的属性musics,用于存放需要展示的音乐信息。
在viewDidLoad方法中通过TRWebUtils类调用requestMusicsByWord:andCallBack:方法,根据用户输入的歌手姓名发送网络请求,解析歌曲数据得到属性self.music数据,刷新界面,代码如下所示:
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- [TRWebUtils requestMusicsByWord:self.word andCallBack:^(id obj) {
- self.musics = obj;
- [self.tableView reloadData];
- }];
- }
用户所挑选的图片将呈现在下方的ScrollView上面,因此需要在弹出ImagePickerController时创建一个ScrollView和一个确定按钮,当点击确定按钮时表示用户完成图片选择,返回之前的界面,该功能需要在navigationController:didShowViewController:animated:方法中实现,代码如下所示:
- -(void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
- //创建确定按钮
- UIImageView *iv = [[UIImageView alloc]initWithFrame:CGRectMake(0, 450, 320, 20)];
- [iv setBackgroundColor:[UIColor yellowColor]];
- UIButton *btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
- btn.frame = CGRectMake(270, 0, 50, 20);
- [btn setTitle:@"确定" forState:UIControlStateNormal];
- [btn addTarget:self action:@selector(finishPickImage) forControlEvents:UIControlEventTouchUpInside];
- btn.tag = 1;
- [iv addSubview:btn];
- iv.userInteractionEnabled = YES;
- [viewController.view addSubview:iv];
- //创建呈现挑选图片的ScrollView
- self.pickerScrollView = [[UIScrollView alloc]init];
- self.pickerScrollView.frame = CGRectMake(0, 470, 320,80);
- [self.pickerScrollView setBackgroundColor:[UIColor grayColor]];
- [viewController.view addSubview:self.pickerScrollView];
- }
于表视图的每个Cell需要展示歌曲的信息,所以这里需要自定义一个Cell,因此创建一个TRMusicCell类,继承至UITableViewCell类,需要显示专辑封面,歌曲名、歌手名以及专辑名,代码如下所示:
- //TRMusicCell.h
- @interface TRMusicCell : UITableViewCell
- @property (weak, nonatomic) IBOutlet UILabel *singerLabel;
- @property (weak, nonatomic) IBOutlet UIImageView *albumIV;
- @property (weak, nonatomic) IBOutlet UILabel *nameLabel;
- @property (weak, nonatomic) IBOutlet UILabel *albumLabel;
- @property (nonatomic, strong)TRMusicInfo *music;
- @end
- //TRMusicCell.m
- @implementation TRMusicCell
- -(void)layoutSubviews{
- [super layoutSubviews];
- self.nameLabel.text = self.music.name;
- self.singerLabel.text = self.music.singerName;
- self.albumLabel.text = self.music.albumName;
- NSLog(@"%@",self.music.albumImagePath);
- //从网络获取图片比较耗时,将此操作放入一个操作队列异步执行
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
- NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:self.music.albumImagePath]];
- UIImage *image = [UIImage imageWithData:imageData];
- dispatch_async(dispatch_get_main_queue(), ^{
- self.albumIV.image = image;
- });
- });
- }
- @end
最后实现表视图的数据源方法和delegate委托方法,代码如下所示:
- - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
- {
- return self.musics.count;
- }
- - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
- {
- static NSString *CellIdentifier = @"Cell";
- TRMusicCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
- TRMusicInfo *music = self.musics[indexPath.row];
- cell.music = music;
- return cell;
- }
- //当用户选择某一首歌曲的时候跳转到音乐播放界面
- -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
- TRMusicInfo *m = self.musics[indexPath.row];
- [self performSegueWithIdentifier:@"playvc" sender:m];
- }
步骤三:实现TRPlayViewController的音乐下载和播放功能
音乐播放视图控制器TRPlayViewController有一个TRMusicInfo类型的公开属性music,用于记录用户从上一个界面选择的音乐信息,代码如下所示:
- @interface TRPlayViewController : UIViewController
- @property (nonatomic, strong)TRMusicInfo *music;
- @end
该视图控制器的私有属性,代码如下所示:
- @interface TRPlayViewController ()
- @property (weak, nonatomic) IBOutlet UISlider *mySlider;
- @property (nonatomic, strong)NSMutableData *allData;
- @property (nonatomic, strong)AVAudioPlayer *player;
- @property (nonatomic, strong)NSTimer *myTimer;
- @property (nonatomic, strong) NSURLConnection *conn;
- @property (nonatomic) NSUInteger fileLength;
- @end
其次在TRPlayViewController的viewDidLoad方法中通过TRWebUtils类调用requestMusicDetailByMusic:andCallBack:方法,根据音乐信息获取到音乐的下载地址和歌词地址,代码如下所示:
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- [TRWebUtils requestMusicDetailByMusic:self.music andCallBack:^(id obj) {
- [self downloadMusic];
- }];
- }
然后通过音乐下载地址发送下载请求,将发送下载请求的代码封装在downloadMusic方法中,代码如下所示:
- -(void)downloadMusic{
- NSURL *url = [NSURL URLWithString:self.music.musicPath];
- NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
- //对象创建出来时异步请求已经发出
- self.conn = [[NSURLConnection alloc]initWithRequest:request delegate:self];
- if (!self.conn) {
- NSLog(@"链接创建失败");
- }
- }
接下来实现NSURLConnectionDelegate的协议方法,在connection:didReceiveResponse:方法中解析头文件,获取到文件的大小并初始化self.allData属性,代码如下所示:
- //接收到服务器响应
- -(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
- NSHTTPURLResponse *res = (NSHTTPURLResponse*)response;
- NSDictionary *headerDic = res.allHeaderFields;
- NSLog(@"%@",headerDic);
- self.fileLength = [[headerDic objectForKey:@"Content-Length"] intValue];
- self.allData = [NSMutableData data];
- }
在connection:didReceiveData:方法中将下载到的音乐数据保存在self.allData中,并且创建音乐播放器并播放歌曲,实现边下载边播放的功能,代码如下所示:
- //接收到数据
- -(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
- // NSLog(@"%d",data.length);
- [self.allData appendData:data];
- //初始化player对象
- if (self.allData.length>1024*150&&!self.player) {
- NSLog(@"开始播放");
- self.player = [[AVAudioPlayer alloc]initWithData:self.allData error:Nil];
- [self.player play];
- float allTime = self.player.duration*self.fileLength/self.allData.length;
- self.mySlider.maximumValue = allTime;
- }
- }
在connectionDidFinishLoading:方法中将音乐的数据存入本地,代码如下所示:
- //加载完成
- -(void)connectionDidFinishLoading:(NSURLConnection *)connection{
- NSLog(@"下载完成");
- //下载完成之后更新准确的歌曲时长
- self.mySlider.maximumValue = self.player.duration;
- NSString *filePath = [NSString stringWithFormat:@"/Users/Vivian/Desktop/%@",self.music.name];
- filePath = [filePath stringByAppendingPathExtension:@"mp3"];
- [self.allData writeToFile:filePath atomically:YES];
- }
最后在downloadMusic方法中开启一个计时器,更新进度条的显示,即音乐的播放进度,代码如下所示:
- -(void)downloadMusic{
- NSURL *url = [NSURL URLWithString:self.music.musicPath];
- NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
- //对象创建出来时异步请求已经发出
- self.conn = [[NSURLConnection alloc]initWithRequest:request delegate:self];
- if (!self.conn) {
- NSLog(@"链接创建失败");
- }
- //开启一个计时器,更新界面的进度条
- self.myTimer = [NSTimer scheduledTimerWithTimeInterval:.1 target:self selector:@selector(updateUI) userInfo:Nil repeats:YES];
- }
- -(void)viewDidDisappear:(BOOL)animated{
- [self.myTimer invalidate];
- }
- -(void)updateUI{
- self.mySlider.value = self.player.currentTime;
- }
1.4 完整代码
本案例中,TRViewController.m文件中的完整代码如下所示:
- #import "TRViewController.h"
- #import "TRMusicListViewController.h"
- @interface TRViewController ()
- @property (weak, nonatomic) IBOutlet UITextField *myTF;
- @end
- @implementation TRViewController
- -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
- TRMusicListViewController *vc = segue.destinationViewController;
- vc.word = self.myTF.text;
- }
- @end
本案例中,TRMusicListViewController.h文件中的完整代码如下所示:
- #import <UIKit/UIKit.h>
- @interface TRMusicListViewController : UITableViewController
- @property (nonatomic, copy)NSString *word;
- @end
本案例中,TRMusicListViewController.m文件中的完整代码如下所示:
- #import "TRMusicCell.h"
- #import "TRMusicListViewController.h"
- #import "TRParser.h"
- #import "TRMusicInfo.h"
- #import "TRWebUtils.h"
- #import "TRPlayViewController.h"
- @interface TRMusicListViewController ()
- @property (nonatomic, strong)NSMutableArray *musics;
- @end
- @implementation TRMusicListViewController
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- [TRWebUtils requestMusicsByWord:self.word andCallBack:^(id obj) {
- self.musics = obj;
- [self.tableView reloadData];
- }];
- }
- #pragma mark - Table view data source
- - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
- {
- return self.musics.count;
- }
- - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
- {
- static NSString *CellIdentifier = @"Cell";
- TRMusicCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
- TRMusicInfo *music = self.musics[indexPath.row];
- cell.music = music;
- return cell;
- }
- -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
- TRMusicInfo *m = self.musics[indexPath.row];
- [self performSegueWithIdentifier:@"playvc" sender:m];
- }
- - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
- {
- TRPlayViewController *vc = segue.destinationViewController;
- vc.music = sender;
- }
- @end
本案例中,TRPlayViewController.h文件中的完整代码如下所示:
- #import <UIKit/UIKit.h>
- #import "TRMusicInfo.h"
- @interface TRPlayViewController : UIViewController
- @property (nonatomic, strong)TRMusicInfo *music;
- @end
本案例中,TRPlayViewController.m文件中的完整代码如下所示:
- #import "TRPlayViewController.h"
- #import "TRWebUtils.h"
- #import <AVFoundation/AVFoundation.h>
- @interface TRPlayViewController ()
- @property (weak, nonatomic) IBOutlet UISlider *mySlider;
- @property (nonatomic, strong)NSMutableData *allData;
- @property (nonatomic, strong)AVAudioPlayer *player;
- @property (nonatomic, strong)NSTimer *myTimer;
- @property (nonatomic, strong) NSURLConnection *conn;
- @property (nonatomic) NSUInteger fileLength;
- @end
- @implementation TRPlayViewController
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- [TRWebUtils requestMusicDetailByMusic:self.music andCallBack:^(id obj) {
- [self downloadMusic];
- }];
- }
- -(void)downloadMusic{
- NSURL *url = [NSURL URLWithString:self.music.musicPath];
- NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
- //对象创建出来时 异步请求已经发出
- self.conn = [[NSURLConnection alloc]initWithRequest:request delegate:self];
- if (!self.conn) {
- NSLog(@"链接创建失败");
- }
- //开启一个计时器,更新界面的进度条
- self.myTimer = [NSTimer scheduledTimerWithTimeInterval:.1 target:self selector:@selector(updateUI) userInfo:Nil repeats:YES];
- }
- -(void)viewDidDisappear:(BOOL)animated{
- [self.myTimer invalidate];
- }
- -(void)updateUI{
- self.mySlider.value = self.player.currentTime;
- }
- #pragma mark NSURLConnectionDelegate
- //接收到服务器响应
- -(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
- NSHTTPURLResponse *res = (NSHTTPURLResponse*)response;
- NSDictionary *headerDic = res.allHeaderFields;
- NSLog(@"%@",headerDic);
- self.fileLength = [[headerDic objectForKey:@"Content-Length"] intValue];
- self.allData = [NSMutableData data];
- }
- //接收到数据
- -(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
- // NSLog(@"%d",data.length);
- [self.allData appendData:data];
- //初始化player对象
- if (self.allData.length>1024*150&&!self.player) {
- NSLog(@"开始播放");
- self.player = [[AVAudioPlayer alloc]initWithData:self.allData error:Nil];
- [self.player play];
- float allTime = self.player.duration*self.fileLength/self.allData.length;
- self.mySlider.maximumValue = allTime;
- }
- }
- //加载完成
- -(void)connectionDidFinishLoading:(NSURLConnection *)connection{
- NSLog(@"下载完成");
- //下载完成之后更新准确的歌曲时长
- self.mySlider.maximumValue = self.player.duration;
- NSString *filePath = [NSString stringWithFormat:@"/Users/Vivian/Desktop/%@",self.music.name];
- filePath = [filePath stringByAppendingPathExtension:@"mp3"];
- [self.allData writeToFile:filePath atomically:YES];
- }
- @end
本案例中,TRMusicCell.h文件中的完整代码如下所示:
- #import <UIKit/UIKit.h>
- #import "TRMusicInfo.h"
- @interface TRMusicCell : UITableViewCell
- @property (weak, nonatomic) IBOutlet UILabel *singerLabel;
- @property (weak, nonatomic) IBOutlet UIImageView *albumIV;
- @property (weak, nonatomic) IBOutlet UILabel *nameLabel;
- @property (weak, nonatomic) IBOutlet UILabel *albumLabel;
- @property (nonatomic, strong)TRMusicInfo *music;
- @end
本案例中,TRMusicCell.m文件中的完整代码如下所示:
- @implementation TRMusicCell
- -(void)layoutSubviews{
- [super layoutSubviews];
- self.nameLabel.text = self.music.name;
- self.singerLabel.text = self.music.singerName;
- self.albumLabel.text = self.music.albumName;
- NSLog(@"%@",self.music.albumImagePath);
- //从网络获取图片比较耗时,将此操作放入一个操作队列异步执行
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
- NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:self.music.albumImagePath]];
- UIImage *image = [UIImage imageWithData:imageData];
- dispatch_async(dispatch_get_main_queue(), ^{
- self.albumIV.image = image;
- });
- });
- }
- @end
本案例中,TRMusicInfo.h文件中的完整代码如下所示:
- #import <Foundation/Foundation.h>
- @interface TRMusicInfo : NSObject
- @property (nonatomic, copy)NSString *name;
- @property (nonatomic, copy)NSString *singerName;
- @property (nonatomic, copy)NSString *albumName;
- @property (nonatomic, copy)NSString *songID;
- @property (nonatomic, copy)NSString *albumImagePath;
- @property (nonatomic, copy)NSString *musicPath;
- @property (nonatomic, copy)NSString *lrcPath;
- @end
本案例中,TRParser.h文件中的完整代码如下所示:
- #import <Foundation/Foundation.h>
- #import "TRMusicInfo.h"
- @interface TRParser : NSObject
- + (NSMutableArray *)parseMusicInfoByArray:(NSArray *)arr;
- + (void)parseMusicDetailByDic:(NSDictionary *)dic andMusic:(TRMusicInfo *)music;
- @end
本案例中,TRParser.m文件中的完整代码如下所示:
- #import "TRParser.h"
- #import "TRMusicInfo.h"
- @implementation TRParser
- +(NSMutableArray *)parseMusicInfoByArray:(NSArray *)arr{
- NSMutableArray *musics = [NSMutableArray array];
- for (NSDictionary *musicDic in arr) {
- TRMusicInfo *mi = [[TRMusicInfo alloc]init];
- mi.name = [musicDic objectForKey:@"song"];
- mi.singerName = [musicDic objectForKey:@"singer"];
- mi.albumName = [musicDic objectForKey:@"album"];
- mi.songID = [musicDic objectForKey:@"song_id"];
- mi.albumImagePath = [musicDic objectForKey:@"albumPicSmall"];
- [musics addObject:mi];
- }
- return musics;
- }
- +(void)parseMusicDetailByDic:(NSDictionary *)dic andMusic:(TRMusicInfo *)music{
- NSDictionary *dataDic = [dic objectForKey:@"data"];
- NSArray *songListArr = [dataDic objectForKey:@"songList"];
- NSDictionary *musicDic = [songListArr lastObject];
- NSString *musicPath = [musicDic objectForKey:@"showLink"];
- music.musicPath = musicPath;
- music.lrcPath = [NSString stringWithFormat:@"http://ting.baidu.com%@",[musicDic objectForKey:@"lrcLink"]];
- }
- @end
本案例中,TRWebUtils.h文件中的完整代码如下所示:
- #import <Foundation/Foundation.h>
- #import "TRMusicInfo.h"
- typedef void (^MyCallback)(id obj);
- @interface TRWebUtils : NSObject
- + (void)requestMusicsByWord:(NSString *)word andCallBack:(MyCallback)callback;
- + (void)requestMusicDetailByMusic:(TRMusicInfo *)music andCallBack:(MyCallback)callback;
- @end
本案例中,TRWebUtils.m文件中的完整代码如下所示:
- #import "TRWebUtils.h"
- #import "TRParser.h"
- @implementation TRWebUtils
- + (void)requestMusicsByWord:(NSString *)word andCallBack:(MyCallback)callback{
- NSString *path = [NSString stringWithFormat:@"http://mp3.baidu.com/dev/api/?tn=getinfo&ct=0&word=%@&ie=utf-8&format=json",word];
- path = [path stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
- NSURL *url = [NSURL URLWithString:path];
- NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
- [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
- NSArray *arr = [NSJSONSerialization JSONObjectWithData:data options:0 error:Nil];
- if (arr.count==0) {
- [TRWebUtils requestMusicsByWord:word andCallBack:callback];
- }
- NSMutableArray *musics = [TRParser parseMusicInfoByArray:arr];
- callback(musics);
- }];
- }
- + (void)requestMusicDetailByMusic:(TRMusicInfo *)music andCallBack:(MyCallback)callback{
- NSString *path = [NSString stringWithFormat:@"http://ting.baidu.com/data/music/links?songIds=%@",music.songID];
- NSLog(@"%@",path);
- NSURL *url = [NSURL URLWithString:path];
- NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
- [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
- NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:data options:0 error:Nil];
- [TRParser parseMusicDetailByDic:dic andMusic:music];
- callback(music);
- }];
- }
- @end