本文主要分享下楼主在学习Swift编程过程中,对GitHub上的一个开源app BaiduFM的研究心得。






项目地址:https://github.com/belm/BaiduFM-Swift
一、项目简介
项目通过使用百度音乐的API实现了播放、下载与收藏音乐的FM基本功能。同时实现了歌词滚动,显示实时进度条,支持后台播放,锁屏显示歌曲信息及控制播放等附加功能并添加了对Apple Watch的支持。此APP可谓是功能十分强劲,下面楼主就来好好分析下这款APP的代码及功能实现原理。
二、APP IOS部分分析
与楼主之前分析的两款APP相似,这款BaiduFM同样也是基于调用API实现从网络端获取歌曲信息及Url并予以播放这一基本功能。在此我便不再具体分析这一功能的实现方法(不清楚的朋友可以参见楼主之前写的两篇博文:(IOS)Swift Music 程序分析 与 (IOS)Swift2.0 Radio 程序分析)。
这次,本文主要想通过对此APP程序及数据结构上的分析,来探究如何通过程序数据结构的设计,从而以一个高效简洁的代码来达到预期功能,并增强代码对其他功能的扩展性。同时顺带介绍下本APP所使用到的一些第三方库。
1、DataBase
本作与之前分析的两款FM类APP最显著的一个不同是,作者为这款APP设计了一个存储于本地的DateBase。通过对第三方库FMDB的调用,作者在本地建立了一个SQLite数据库用于存放歌曲信息列表。那么,首先楼主就先来介绍下FMDB这个第三方库。
FMDB是以Object-C封装了C语言API的用于在ios设备上生成并管理SQLite的这么一个第三方库。通过调用FMDB库,使用者可以可以很轻松的使用SQL命令来对数据库进行操作。
Github:https://github.com/ccgus/fmdb。
具体的使用说明可以参见博文:http://www.cnblogs.com/wendingding/p/3871848.html。





在本项目中,作者通过建立class BaseDb在本地建立了一个FMDataBase,并通过class SongList:BaseDb建立了本地音乐列表数据库。并通过调用FMDCB的方法创建了诸如func getAll()->[Song]?,func get(sid:String)->Song?等方法(具体参见上图代码)。代码都较为易懂,在此楼主就不做过多解释了,在这之中唯一需要注意的是,在FMDB使用过程中,任何除select以外的操作都视为更新。所以使用的是executeUpdate(,withArgumentsInArray)方法。通过对SongList类的定义,作者可以很容易的通过类的方法对本地数据库进行添加删除修改数据等操作。
2、Model
除了定义了数据库,定义一些APP中所要使用到的Data Model也是在设计程序中一个不可缺少的环节。在这个环节中,作者一共定义了5种Data类型。



其中三个struct分别是:SongInfo,SongLink与Channel。
SongInfo:包含了歌曲id,名字,表演者等信息。
SongLink:包含了歌曲链接,歌词链接,格式等信息
Channel:包含了频道id,名字,序列号等信息



两个class:class Song:NSObject 与 class DataCenter
Song:是数据库用于记录歌曲信息的数据类型
DataCenter:是用于提供存储当前电台信息,当前播放列表信息,播放歌曲信息,数据库操作等一系列操作的类似于model manager角色的对象。同时提供了一个shareDateCenter 的单例用于将自身共享。
3、Common
作者将一些时常会调用到的函数及常量统一装在了这个文件夹下。

Const.swift中就包含了两个通知名及APP所需用到的URL,像这样将常量统一管理,在日后对其进行调试修改及更新时会变得便捷许多。

Utils封装了一个获取文档路径的方法,这样做不但提高了代码的编写效率,同时也增加了代码的可读性。




Common类中则是包含了一些对歌曲url,歌曲图片 ,显示时间,本地歌曲删除及歌词处理的方法。在这之中,作者通过定义及使用了一个通过比对字符串正则表达式的方法来进行lrc歌词文件中时间部分与歌词部分的分割,并返回一个歌词时间一一对应的数组。

举个例子:上图是一个lrc格式的歌词文件。通过将此文件传入函数class func praseSongLrc(lrc:String)->[(lrc:String,time:Int)],最终返回的数组应如下:
ret[0] = (lrc:"Glad You Came", time:0)
ret[1] = (lrc:"The Wanted", time:0)
ret[2] = (lrc:"", time:0)
ret[3] = (lrc:"The sun goes down", time:1)
ret[4] = (lrc:"The stars come out", time:3)
...





最后,在Common文件夹中,作者在HttpRequest类中调用了Alamofire和SwiftyJson两个第三方库定义了一系列通过网络请求获取歌曲信息及下载等一系列方法。与之前楼主分析的两款APP不同,这款APP并没有使用swift自带的NSURLSession或NSURLConnect来进行网络请求,而是调用了第三方库Alamofire同提供的API来达成网络通信的。下面我就先来简单介绍下Alamofire这个第三方库。
Alamofire是用于Http网络开发的第三方库。它的作者就是大名鼎鼎的第三方库AFNetworking的作者。可以说Alamofire就是Swift版的AFNetworking。
Github:https://github.com/Alamofire/Alamofire
Alamofire的最新版本是3.0,支持iOS 8+, Mac OS X 10.9+, watchOS 2.0, Xcode 7 and Swift 2.0,可以通过CocoaPods,Carthage等多种工具倒入到项目文件。

这是一个简单的使用Alamofire.request方法获取响应并使用.responseJSON对响应结果进行处理的例子。更多的调用API的例子,各位看官可以去Github上观看Alamofire的详细教程指南。
通过上面的这一简单的例子,不难发现相比于NSURLSession,Alamofire对URL请求的及返回结果的处理是如此的方便。即无需繁复定义繁琐的session及task,同时再配合SwiftyJSON库使用时,可以极大的减少对Json格式数据的处理时所用到的拆包,转型等操作。
接着楼主就来介绍下这款同样非常好用的第三方库SwiftyJSON。
SwiftyJSON是一款用于处理JSON