(IOS)Swift2.0 Radio 程序分析
本文主要分享下楼主在学习Swift编程过程中,对GitHub上的一个开源项目Swift Radio的研究心得。
项目地址:https://github.com/swiftcodex/Swift-Radio-Pro
一、界面
在这个项目中一共包含了6个界面控制器,其中包含了5个用于分别显示电台频道(Swift Radio)、正在播放(Now Playing View)、电台信息(Info View Controller)、app信息(Menu View Controller)和app特征及联系邮箱(About View Controller)的View Controller及一个Navigation Controller。
二、电台歌曲来源及实现原理
本项目通过调用http://www.last.fm/api提供的API从而实现电台功能。楼主将对其调用的API进行简单的介绍及分析。
1)http://[yoururl.com]/json/stations.json 用于获取电台信息,返回格式为JSON。
本项目中, 作者并未使用此API,而是内置JSON格式的电台数据。
2)http://ws.audioscrobbler.com/2.0/?method=track.getInfo&api_key=[api_key]&artist=[artist]&track=[track]&format=json 通过传递api_key,aritst和track三个参数来获取歌曲信息。
例如:http://ws.audioscrobbler.com/2.0/?method=track.getInfo&api_key=9a267c245324cfa4f887366d497d3dd3&artist=The%20Gossip&track=Coal%20To%20Diamonds&format=json
其中name为歌曲名,artist为歌手信息,album为专辑信息。
本项目中, 作者通过获取正在播放的MPMoviePlayerController()中的Metadata得到artist和track参数,再通过将参数传递到API中,获得完整的歌曲信息。
代码具体实现
1) SwiftRadio-Settings.swift
在SwiftRadio-Settings.swift文件中,作者定义了DEBUG_LOG用于判断是否需要显示调试日志。而后又定义了useLocalStatons来进行判断是否使用本地电台数据,如果useLocalStatons为false,则通过stationDataURL来获取电台信息。接着又给出 了apiKey和apiSecret两个参数以备调用前文获取歌曲信息API时使用(apiSecret并未被使用到)。
2) stations.json
这个文件为本地电台信息,通过修改可以增加或删减电台。其中name是电台名称,streamURL是电台的URL,imageURL是电台图片的URL(因为是本地电台,所以图片都已保存在项目文件中,故imageURL一项中直接给了电台图片文件对应的名称)。
3) RadioStation.swift
创建了一个RadioStation class包含了从电台JSON数据中获取的电台的个属性参数。同是设置了一个构造器及一个直接将电台JSON数据转成RadioStation实例的方法。
4) track.swift
创建了一个Track结构,包含了6个Track的属性。其中artworkLoaded用于记录歌曲图片是否已获取,isPlaying纪录歌曲是否已在播放。
5) DataManager.swift
DataManager这个类中主要包含了获取和处理网络数据或是本地数据的方法。其中getStationDataWithSuccess(success: ((metaData: NSData!) -> Void))方法通过访问SwiftRadio-Settings.swift中useLocalStations的值来判断是使用本地电台数据还是网络电台数据。getDataFromFileWithSuccess(success: ((data: NSData) -> Void))和getTrackDataWithSuccess(queryURL: String, success: ((metaData: NSData!) -> Void))分别是调用本地及网络电台数据的两个方法。loadDataFromURL(url: NSURL, completion:(data: NSData?, error: NSError?) -> Void)则是实现从网络获取电台数据的方法。通过NSURLSession来获得网络数据,而后将所得数据传给方法参数中的包含的方程以供之后的处理及使用。
6) StationsViewController.swift
在StationsViewController类中,实现了对所得到的电台数据进行分析和拆解并通过UITableView将其显示出来。loadStationsFromJSON()通过调用DataManager.getStationDataWithSuccess(success: ((metaData: NSData!) -> Void))获取电台数据并将其0保存在stations:[RadioStation]中。再通过TableView方法来将所得数据呈现在UITableView上。通过重写prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)方法来完成将选中的电台传递给NowPlayingViewController。同时通过完成NowPlayingViewControllerDelegate的两个方法artworkDidUpdate(track: Track)和songMetaDataDidUpdate(track: Track)来获取和显示当前播放歌曲的信息。
7) NowPlayingViewController.swift
创建一个radioPlayer = MPMoviePlayerController()并对其进行设置。当调用stationDidChange()方法时,radioPlayer播放当前电台的媒体流。
metadataUpdated(n: NSNotification)方法用于获取radioPlayer正在播放音乐的metadata,通过进行简单的处理获得正在播放音乐的title和artist信息。如果发现currentSongName与获取title不符,说明开始播放一首新的歌曲了,调用resetAlbumArtwork()和queryAlbumArt()来获取新的歌曲信息,并用updateLockScreen()来更新锁屏界面,用songMetaDataDidUpdate(self.track)将新的歌曲信息传给StationsViewController。
通过使用API获取歌曲完整信息。
resetAlbumArtwork()中通过调用updateAlbumArtwork()来实现专辑封面的更新,如果获取专辑封面失败,则使用电台封面代替。
通过使用NSURLSessionDownloadTask来下载专辑图片,将下载完的图片存至track.artworkImage并更新封面图片,锁屏界面及将新数据回传给StationsViewController。
用于更新界面上的buttons和labels。
三、项目实现的一些特征分析
1) 动态正在播放图标
调用AnimationFrames class 中createFrames()方法为nowPlayingImageView.animationImages创建对象。在通过startAnimating()方法来实现动画效果。
2) 在app中打开safari
通过UIApplication.shareApplication().openURL(url)来实现。
3) 后台播放、锁屏播放及锁屏显示歌曲信息
系统开始接受远端事件。
允许后台播
锁屏歌曲信息设置及接受锁屏时对歌曲播放或暂停的控制。
四、发现的一些BUG
在XCode 7.0.1 iPhone 6s plus 模拟器运行下发现的BUG:
1) 内置email功能无法使用,每次点击email跳转到mail app后立即崩溃。
2) NowPlayingViewController 界面上的Volume Bar 无法调节音量。
3) 在NowPlayingViewController界面播放音乐途中暂停后返回StationViewController后,StationViewController左下角动态正在播放图标还在继续播放动画,而后如果点击正下方Now Playing Button返回NowPlayingViewController时,界面显示音乐正在播放,可实际上音乐处于暂停状态,需要点击暂停按钮再点击播放按钮才能恢复。
五、后记
楼主曾经在学习Swift时做过一个电台的app,相比于这个app,楼主之前做的那个就有些粗制烂造了。通过了对这个app的学习,不但是我对Swift2.0中一些新的特征有了一个更好的理解,同时还让我感受到了这个项目的作者有着很强的程序员素质。对于代码的设计有着很强的全局考虑,使得代码非常的简洁易懂。在阅读和测试时也几乎没有遇到什么因为代码看起来混乱而导致的理解困难。这种编程的思路和设计程序的方法是值得今后值得借鉴和学习的。