《iOS開發(fā)實戰(zhàn):從零基礎(chǔ)到App Store上架》一書由一線軟件工程師結(jié)合實際應用編寫而成,由淺入深系統(tǒng)地介紹了iOS應用從開發(fā)、調(diào)試到打包、上架的完整過程。本書主體由各個基礎(chǔ)模塊組成,由實戰(zhàn)項目連接,在幫助讀者掌握原理的同時輕松上手開發(fā)出自己的應用。
為方便讀者學習,作者還為本書精心錄制了“7天玩轉(zhuǎn)iOS UI開發(fā)視頻教程”,本視頻教程包括基礎(chǔ)篇、中級篇、高級篇、進階篇、擴展篇5部分,總計36堂課,播放時長超過13小時。此外,本書還提供iOS UI開發(fā)視頻教程源代碼以及本書實例源代碼。
本書的特色是通俗易學,突出實戰(zhàn),提供了大量開發(fā)案例,適合于剛?cè)肼毣蛐率謎OS開發(fā)人員和愛好者、大中專院校學生及iOS培訓班學員,尤其適合有一定語言基礎(chǔ)想要開發(fā)App產(chǎn)品的開發(fā)者。
本書作者琿少在中國唯品會做過多年iOS開發(fā),擁有豐富的開發(fā)經(jīng)驗,這本書是作者琿少在工作之余,利用周末和晚上的時間完成的,傾注了作者半年多的心血,在此對琿少這種無私樂于分享的精神表示敬意。
這本書從零基礎(chǔ)開始,介紹了iOS開發(fā)產(chǎn)品的全過程,在講解敘述上盡量使用了非常簡潔、通俗易懂的語言,非常容易上手和看懂學會。
在講解的過程中使用了大量示例和圖示來表述,結(jié)合開發(fā)經(jīng)驗、技巧和詳盡的代碼注解,同時在各章配合項目開發(fā),讀者可以邊學邊練,盡快掌握實用的開發(fā)技能。
作者還為本書錄制了iOS UI 設(shè)計的視頻教學課程,詳細地講解了App UI設(shè)計開發(fā)的核心內(nèi)容,視頻播放時長超過13個小時,同時提供了全書的源代碼,非常超值。
這是一本專業(yè)且易于學習的iOS開發(fā)實戰(zhàn)書,我認為這本書非常值得一讀,特別是對于從來沒有開發(fā)過iOS App產(chǎn)品的讀者將會有很大幫助。
琿,軟件開發(fā)工程師,擁有多年iOS開發(fā)經(jīng)驗,曾開發(fā)iOS平臺系列——游戲瘋狂越獄1~2、應用物通配貨軟件、VIPExam考試庫、證券財經(jīng)軟件等,現(xiàn)就職于中國唯品會。
第1章 開發(fā)準備 1
1.1 iOS 9新特性簡述 2
1.1.1 新增壓力傳感器編程接口 2
1.1.2 全新的搜索功能API 2
1.1.3 更小、更快——全新的應用瘦身策略 3
1.1.4 使用更加安全的網(wǎng)絡(luò)傳輸協(xié)議 4
1.2 熟悉iOS開發(fā)環(huán)境 4
1.2.1 安裝Xcode開發(fā)工具 4
1.2.2 了解Xcode開發(fā)工具主界面 6
1.2.3 Xcode開發(fā)工具的使用技巧及常用快捷鍵 7
1.3 創(chuàng)建第一個iOS項目 8
1.4 使用Git進行項目版本管理 13
1.4.1 Git與Github簡介 13
1.4.2 注冊GitHub會員 13
1.4.3 使用Xcode創(chuàng)建Git倉庫 14
1.4.4 用Xcode建立本地Git倉庫與GitHub代碼托管平臺的聯(lián)系 16
第2章 基礎(chǔ)UI控件 19
2.1 iOS系統(tǒng)UI框架的介紹 20
2.1.1 MVC設(shè)計模式 20
2.1.2 代理設(shè)計模式 21
2.2 視圖控制器——UIViewController 21
2.2.1 UIViewController的生命周期 21
2.2.2 UIViewController的視圖層級結(jié)構(gòu) 25
2.3 文本控件——UILabel 25
2.3.1 使用UILabel在屏幕上創(chuàng)建一個標簽控件 26
2.3.2 自定義標簽控件的相關(guān)屬性 26
2.3.3 多行顯示的UILabel與換行模式 27
2.4 按鈕控件——UIButton 29
2.4.1 創(chuàng)建一個按鈕來改變屏幕顏色 29
2.4.2 更加多彩的UIButton控件 32
2.5 文本輸入框控件——UITextField 33
2.5.1 在屏幕上創(chuàng)建一個輸入框 33
2.5.2 UITextField的常用屬性介紹 35
2.5.3 UITextField的代理方法 36
2.5.4 實現(xiàn)一個監(jiān)聽輸入信息的用戶名輸入框 37
2.6 開關(guān)控件——UISwitch 38
2.6.1 創(chuàng)建一個開關(guān)控件 38
2.6.2 為UISiwtch控件添加觸發(fā)方法 39
2.7 分頁控制器——UIPageControl 40
2.8 分段控制器——UISegmentedControl 41
2.8.1 UISegmentControl基本屬性的應用 41
2.8.2 對UISegmentedControl中的按鈕進行增、刪、改操作 42
2.8.3 UISegmentedControl中按鈕寬度的自適應 43
2.9 滑塊控件——UISlider 43
2.9.1 UISlider的創(chuàng)建與常規(guī)設(shè)置 44
2.9.2 對UISlider添加圖片修飾 45
2.10 活動指示器控件——UIActivityIndicatorView 45
2.11 進度條控件——UIProgressView 47
2.12 步進控制器——UIStepper 48
2.12.1 步進控制器的基本屬性使用 48
2.12.2 自定義UIStepper按鈕圖片 49
2.13 選擇器控件——UIPickerView 49
2.13.1 創(chuàng)建一個UIPickerView控件 50
2.13.2 UIPickerView選中數(shù)據(jù)時的回調(diào)代理 51
2.14 通過CALayer對視圖進行修飾 52
2.14.1 創(chuàng)建圓角的控件 52
2.14.2 創(chuàng)建帶邊框的控件 52
2.14.3 為控件添加陰影效果 53
2.15 警告控制器——UIAlertController 54
2.15.1 UIAlertController的警告框 54
2.15.2 UIAlertController之活動列表 56
2.16 擴展篇 57
2.16.1 搜索欄控件——UISearchBar 57
2.16.2 日期時間選擇器——UIDatePicker 59
2.16.3 警告視圖——UIAlertView 61
2.16.4 活動列表——UIActionSheet 62
2.17 實戰(zhàn):登錄注冊界面的搭建 62
第3章 高級UI控件 68
3.1 導航控制器——UINavigationController 69
3.1.1 導航控制器的工作原理 69
3.1.2 使用導航控制器進行多界面搭建 70
3.1.3 導航欄UINavigationBar 73
3.1.4 導航按鈕UIBarButtonItem 74
3.1.5 導航控制器的工具欄 77
3.1.6 iOS 8之后導航控制器的一些有趣功能 77
3.2 標簽控制器——UITabBarController 78
3.2.1 標簽控制器的工作原理 78
3.2.2 標簽控制器的基礎(chǔ)用法解析 78
3.2.3 關(guān)于UITabBarItem的使用 80
3.3 滾動視圖——UIScrollView 81
3.3.1 使用UIScrollView展示視圖內(nèi)容 81
3.3.2 UIScrollView的代理方法 83
3.4 網(wǎng)絡(luò)視圖——UIWebView 84
3.4.1 App網(wǎng)絡(luò)傳輸安全策略 85
3.4.2 通過網(wǎng)絡(luò)請求加載UIWebView 86
3.4.3 通過HTML字符串加載UIWebView 86
3.4.4 通過NSData數(shù)據(jù)加載UIWebView 87
3.4.5 UIWebView中常用方法解析 88
3.4.6 UIWebView的代理方法 89
3.5 表格視圖——UITableView 90
3.5.1 UITableView的創(chuàng)建與復用機制 90
3.5.2 創(chuàng)建一個表格視圖UITableView 91
3.5.3 關(guān)于表格數(shù)據(jù)的載體UITableViewCell 93
3.5.4 設(shè)置UITableView的行高和頭尾視圖 95
3.5.5 UITableView的用戶交互行為 96
3.5.6 為UITableView添加索引欄 99
3.6 復雜布局視圖——UICollectionView 99
3.6.1 UICollectionView控件的優(yōu)勢與布局方式 100
3.6.2 使用UICollectionView進行九宮格式的布局 100
3.6.3 創(chuàng)建更加靈活的流式布局 102
3.6.4 自定義UICollectionViewFlowLayout進行參差瀑布流布局 103
3.6.5 使用UICollectionView進行圓環(huán)布局 106
3.7 實戰(zhàn):開發(fā)一款手機網(wǎng)頁瀏覽器 109
3.7.1 網(wǎng)頁瀏覽器工程的搭建 110
3.7.2 核心網(wǎng)頁視圖的設(shè)計 111
3.7.3 歷史記錄界面的設(shè)計 119
3.7.4 收藏界面的設(shè)計 122
3.7.5 啟動頁面、圖標及應用名稱的相關(guān)優(yōu)化 124
第4章 網(wǎng)絡(luò)編程 127
4.1 使用NSURLConnection請求網(wǎng)絡(luò)數(shù)據(jù) 128
4.1.1 申請一個免費的API服務(wù) 128
4.1.2 使用NSURLConnection進行API服務(wù)數(shù)據(jù)的獲取 131
4.1.3 使用NSURLConnection進行異步網(wǎng)絡(luò)請求 132
4.1.4 使用NSURLConnection類通過代理回調(diào)的方式異步進行網(wǎng)絡(luò)請求 134
4.2 設(shè)計封裝一個更加易用的網(wǎng)絡(luò)請求類 135
4.2.1 設(shè)計自定義的網(wǎng)絡(luò)請求連接類 135
4.2.2 設(shè)計自定義的網(wǎng)絡(luò)請求連接管理類 136
4.3 JSON類型數(shù)據(jù)的解析與數(shù)據(jù)模型的設(shè)計 139
4.3.1 JSON數(shù)據(jù)簡介 139
4.3.2 在iOS中解析JSON數(shù)據(jù) 141
4.3.3 數(shù)據(jù)模型Model類的設(shè)計 142
4.4 使用CocoaPods進行第三方庫的管理 146
4.4.1 在MAC上安裝CocoaPods 146
4.4.2 用CocoaPods搭建一個使用第三方網(wǎng)絡(luò)請求框架AFNetworking的工程 148
4.5 使用AFNetworking進行網(wǎng)絡(luò)請求 150
4.5.1 詳解HTTP/HTTPS協(xié)議 150
4.5.2 使用AFNetworking進行網(wǎng)絡(luò)請求 151
4.6 實戰(zhàn):開發(fā)“笑一笑”應用程序 153
4.6.1 工程項目框架的搭建 154
4.6.2 “笑一笑”界面數(shù)據(jù)載體cell的設(shè)計 155
4.6.3 “笑一笑”界面的搭建 157
4.6.4 實現(xiàn)下拉刷新與加載更多功能 162
4.6.5 “趣圖吧”界面數(shù)據(jù)載體cell的設(shè)計 164
4.6.6 “趣圖吧”界面的設(shè)計 167
第5章 音視頻開發(fā) 172
5.1 iOS音頻開發(fā)基礎(chǔ)——AVAudioPlayer類的使用 173
5.1.1 使用AVAudioPlayer進行MP3音頻文件的播放 173
5.1.2 進行音頻播放相關(guān)屬性的控制 175
5.1.3 后臺播放音頻及用戶交互的優(yōu)化 180
5.2 iOS視頻開發(fā)基礎(chǔ) 184
5.2.1 使用MPMoviePlayerController向應用中嵌入視頻模塊 184
5.2.2 MPMoviePlayerController常用屬性與方法解析 185
5.3 視頻播放器視圖控制器——MPMoviePlayerViewController 189
5.4 AVPlayerViewController視頻播放框架與畫中畫開發(fā)技術(shù) 191
5.4.1 使用AVPlayerViewController進行視頻播放 191
5.4.2 iPad的畫中畫播放技術(shù) 193
5.5 實戰(zhàn):“天后王菲”音頻播放器的開發(fā) 195
5.5.1 工程搭建與LRC歌詞文件簡介 196
5.5.2 LRC歌詞解析引擎的設(shè)計 197
5.5.3 核心播放器引擎的設(shè)計 201
5.5.4 歌曲列表與歌詞顯示視圖界面的設(shè)計 208
5.5.5 播放器主頁面的實現(xiàn) 213
5.5.6 后臺播放音頻用戶交互的處理 219
第6章 動畫開發(fā) 221
6.1 使用UIImageView播放圖片組幀動畫 222
6.2 UIView層動畫的應用 223
6.2.1 執(zhí)行UIView層過渡動畫的三個類方法 223
6.2.2 創(chuàng)建UIView層的阻尼動畫 225
6.2.3 動畫參數(shù)配置與組合動畫 225
6.2.4 UIView層過渡動畫支持的屬性 227
6.3 使用commit方式進行UIView層動畫的創(chuàng)建 228
6.3.1 使用commit方式進行UIView層過渡動畫的創(chuàng)建 228
6.3.2 兩種UIView層動畫創(chuàng)建方式的優(yōu)劣 230
6.4 UIView的轉(zhuǎn)場動畫 230
6.4.1 重繪UIView視圖時使用的轉(zhuǎn)場動畫 230
6.4.2 切換UIView視圖時使用的轉(zhuǎn)場動畫 231
6.5 核心動畫編程技術(shù)——CoreAnimation 232
6.5.1 錨點對視圖控件幾何位置的影響 233
6.5.2 色彩梯度層——CAGradientLayer 234
6.5.3 視圖拷貝層——CAReplicatorLayer 235
6.5.4 圖形渲染層——CAShapeLayer 236
6.5.5 文本繪制層——CATextLayer 237
6.5.6 CAAnimation動畫體系介紹 238
6.5.7 使用CABasicAnimation創(chuàng)建基礎(chǔ)動畫 240
6.5.8 使用CAKeyframeAnimation類創(chuàng)建關(guān)鍵幀動畫 242
6.5.9 CALayer層的轉(zhuǎn)場動畫——CATransition 243
6.5.10 CALayer層的組合動畫——CAAnimationGroup 245
6.5.11 CATransform3D變換的應用 246
6.6 炫酷的粒子效果 248
6.6.1 粒子發(fā)射器——CAEmitterLayer 248
6.6.2 粒子單元——CAEmitterCell 250
6.6.3 創(chuàng)建粒子火焰動畫 251
6.7 播放GIF動態(tài)圖 253
6.7.1 使用UIWebView進行GIF動態(tài)圖播放 253
6.7.2 使用UIImageView幀動畫進行GIF動態(tài)圖播放 254
6.8 實戰(zhàn):小游戲Flappy Bird的設(shè)計與開發(fā) 256
6.8.1 小鳥對象的設(shè)計 257
6.8.2 游戲開始界面的設(shè)計 259
6.8.3 游戲結(jié)束界面的設(shè)計 261
6.8.4 Flappy Bird游戲主框架的搭建 262
第7章 傳感器開發(fā) 270
7.1 為應用程序添加手機密碼及指紋識別的安全驗證 271
7.1.1 使用手機密碼為應用程序添加安全驗證 271
7.1.2 使用用戶指紋為應用程序添加安全驗證 273
7.2 使用加速度傳感器、螺旋儀傳感器與磁力傳感器獲取設(shè)備空間狀態(tài) 274
7.2.1 使用UIAccelerometer獲取設(shè)備空間狀態(tài) 274
7.2.2 使用CoreMotion框架獲取設(shè)備空間狀態(tài)信息 275
7.3 距離傳感器的應用 278
7.4 iOS藍牙開發(fā)技術(shù) 279
7.4.1 中心設(shè)備管理類CBCentralManager 280
7.4.2 外圍設(shè)備管理類CBPeripheralManager 285
7.5 GPS應用與地圖編程技術(shù) 289
7.5.1 進行設(shè)備地理位置定位 289
7.5.2 原生地圖開發(fā)技術(shù) 292
7.5.3 在地圖中添加大頭針及標注 294
7.5.4 在地圖視圖中添加覆蓋物 297
7.5.5 在地圖中進行線路導航與附近興趣點檢索 299
7.6 實戰(zhàn):簡易藍牙對戰(zhàn)五子棋 304
7.6.1 游戲核心通信類的設(shè)計 304
7.6.2 棋盤瓦片的設(shè)計 314
7.6.3 核心游戲視圖與游戲核心邏輯的設(shè)計 315
7.6.4 核心游戲視圖控制器的設(shè)計 325
第8章 界面布局 329
8.1 iOS中傳統(tǒng)的UIViewAutoresizing布局模式 330
8.1.1 通過代碼來設(shè)置視圖控件的UIViewAutoresizing模式 330
8.1.2 在xib文件中可視化地配置控件的autoresizing屬性 332
8.2 Autolayout自動布局框架 333
8.2.1 初識Autolayout 334
8.2.2 Autolayout的屬性意義與一個簡單的自動布局示例 335
8.2.3 使用Objective-C風格的方法進行代碼Autolayout布局 338
8.2.4 使用格式化的字符串進行Autolayout布局對象的創(chuàng)建 341
8.2.5 與約束相關(guān)的幾個方法 343
8.2.6 使用Autolayout設(shè)計一個高度自適應的聊天輸入框及動畫優(yōu)化 343
8.2.7 使用第三方庫Masonry進行Autolayout約束布局 345
第9章 數(shù)據(jù)持久化 351
9.1 使用plist文件進行輕量級數(shù)據(jù)持久化管理 352
9.1.1 在工程中讀取plist文件數(shù)據(jù) 352
9.1.2 在程序沙盒Doucments目錄中創(chuàng)建和使用plist文件 353
9.1.3 使用NSUserDefaults類進行數(shù)據(jù)持久化 354
9.2 使用歸檔技術(shù)進行數(shù)據(jù)模型持久化 356
9.2.1 進行單一系統(tǒng)數(shù)據(jù)類型的歸檔與解歸檔操作 356
9.2.2 對多個對象進行數(shù)據(jù)歸檔 357
9.2.3 進行自定義數(shù)據(jù)模型的歸檔 358
9.3 小型數(shù)據(jù)庫SQLite在iOS開發(fā)中的應用 360
9.3.1 SQLite數(shù)據(jù)庫常用語法介紹 360
9.3.2 使用iOS原生框架sqlite3對SQLite數(shù)據(jù)庫進行操作 362
9.4 核心數(shù)據(jù)管理框架CoreData的使用 367
9.4.1 使用CoreData設(shè)計數(shù)據(jù)模型 367
9.4.2 CoreData編程框架中3個重要的類 370
5.5 實戰(zhàn):“天后王菲”音頻播放器的開發(fā)
在本小節(jié)中讀者將通過開發(fā)一款音樂播放器類應用程序?qū)W習到更多技巧,通過歌詞同步引擎的開發(fā),讀者將初步掌握iOS中數(shù)據(jù)解析的相關(guān)方法。
5.5.1 工程搭建與LRC歌詞文件簡介
一款流行的音樂播放器軟件,在播放音樂時同步顯示歌詞是必備的功能,其實這些播放器軟件都實現(xiàn)了一個歌詞解析引擎,通過歌詞解析引擎將LRC文件解析為程序中需要的歌詞對象。
LRC是Lyric單詞的縮寫,是音頻同步歌詞文件的一種協(xié)議格式。LRC文件中通過標簽的形式將歌曲的專輯、歌手、每個時間點對應的歌詞記錄其中,音頻播放器通過解析這些數(shù)據(jù)來同步顯示歌詞。一個LRC歌詞文件其內(nèi)容格式大致如下所示:
[ti:匆匆那年]
[ar:王菲]
[al:電影《匆匆那年》主題曲]
[t_time:(04:08)]
[00:32.16] 匆匆那年 我們究竟說了幾遍
[00:34.82] 再見之后再拖延
[00:37.62] 可惜誰有沒有愛過
[00:39.37] 不是一場七情上面的雄辯
[00:43.42] 匆匆那年 我們一時匆忙撂下
[00:45.82] 難以承受的諾言 只有等別人兌現(xiàn)
[00:54.69] 不怪那吻痕 還沒積累成繭
[01:00.44] 擁抱著冬眠 也沒能羽化再成仙
[01:05.74] 不怪這一段情沒空反復再排練
[01:11.24] 是歲月寬容恩賜 反悔的時間
[01:22.38] 如果再見不能紅著眼
[01:25.38] 是否還能紅著臉
[01:28.24] 就像那年匆促刻下
[01:30.14] 永遠一起那樣美麗的謠言
[01:33.49] 如果過去還值得眷戀
[01:36.89] 別太快冰釋前嫌
[01:39.44] 誰甘心就這樣
[01:42.39] 彼此無掛也無牽
[01:45.93] 我們要互相虧欠
[01:50.94] 要不然憑何懷念
[02:02.25] 匆匆那年 我們見過太少世面
[02:04.79] 只愛看同一張臉
[02:07.65] 那么莫名其妙 那么討人歡喜
[02:10.25] 鬧起來又太討厭
[02:13.30] 相愛那年活該匆匆
[02:15.51] 因為我們不懂頑固的諾言
[02:18.85] 只是分手的前言
[02:24.65] 不怪那天太冷 淚滴水成冰
[02:30.55] 春風也一樣沒吹進凝固的照片
[02:35.70] 不怪每一個人沒能完整愛一遍
[02:41.35] 是歲月善意落下 殘缺的懸念
[02:52.36] 如果再見不能紅著眼 是否還能紅著臉
歌詞文件中ti標簽對應歌曲的名稱,ar標簽對應歌手名稱,al標簽對應歌曲專輯。t_time對應歌曲的時間,之后的時間標簽代表某一時刻對應的歌詞。
使用Xcode創(chuàng)建一個名為MyPlayer的工程,向其中導入一些音頻文件及其對應的LRC歌詞文件。需要注意的是,LRC文件的文件名要與對應的歌曲名相同,便于在解析時將歌詞文件與歌曲對應。
在向工程中添加大量文件時,可以通過建立新的引用目錄使工程的目錄結(jié)構(gòu)看起來整齊一些,在Xcode文件導航區(qū)單擊右鍵,選擇New Group選項即可新建一個引用目錄,如圖5-30所示。
5.5.2 LRC歌詞解析引擎的設(shè)計
在Xcode中創(chuàng)建兩個引用目錄Song和LRC,分別用來存放歌曲文件與歌詞文件。設(shè)計一個新的類作為每行歌詞的數(shù)據(jù)模型,使用Xcode新建一個類文件,命名為LRCItem,使其繼承于NSObject。
在LRCItem.h文件中添加如下方法和屬性的聲明。
@interface LRCItem : NSObject
@property (nonatomic) float time;
@property (nonatomic,copy) NSString *lrc;
//排序方法
- (BOOL)isTimeOlderThanAnother:(LRCItem *)item;
@end
上面聲明的屬性和方法中,float是此行歌詞的出現(xiàn)時間,lrc是此行歌詞具體的文本數(shù)據(jù)。IsTimeOlderThanAnother:方法用于行歌詞數(shù)據(jù)模型的排序,這個方法將按照時間先后進行排序。
在LRCItem.m文件中添加方法的實現(xiàn)代碼。
- (BOOL)isTimeOlderThanAnother:(LRCItem *)item{
return self.time > item.time;
}
再新建一個類文件命名為LRCEngine作為歌詞解析引擎,使其繼承于NSObject。在LRCEngine.h文件中引入LRCItem類的頭文件:
#import "LRCItem.h"
在LRCEngine.h文件中聲明如下的屬性與方法:
@interface LRCEngine : NSObject
-(instancetype)initWithFile:(NSString *)fileName;
@property(nonatomic,strong)NSString * author;
@property(nonatomic,strong)NSString * albume;
@property(nonatomic,strong)NSString * title;
-(void)getCurrentLrcInLRCArray:(void(^)(NSArray * lrcArray,int currentIndex))handle atTime:(float)time;
@end
在上面代碼中,initWithFile:方法用于進行歌詞引擎的初始化,flieName參數(shù)為歌詞文件的名稱。author屬性為歌手姓名。albume屬性為專輯的名稱。title屬性為歌曲的名稱。getCurrentLRCInLRCArray:atTime:方法為歌詞引擎的核心方法,其通過傳入一個時間點的值來獲取當前對應的歌詞,在handle函數(shù)塊中將傳入兩個參數(shù),一個是已經(jīng)按時間排序的每行歌詞數(shù)據(jù)的數(shù)組,一個是當前對應的歌詞在數(shù)組中的位置。
在LRCEngine.m文件中聲明一個可變數(shù)組用于存放每行歌詞數(shù)據(jù),代碼如下:
@implementation LRCEngine
{
NSMutableArray * _lrcArray;
}
@end
實現(xiàn)LRCEngine類的初始化方法,代碼如下:
-(instancetype)initWithFile:(NSString *)fileName{
if (self=[super init]) {
_lrcArray = [[NSMutableArray alloc]init];
[self creatDataWithFile:fileName];
}
return self;
}
上面方法中進行數(shù)組對象的初始化操作,creatDataWithFile:方法的實現(xiàn)如下:
-(void)creatDataWithFile:(NSString *)fileName{
//讀取文件
NSString * lrcPath = [[NSBundle mainBundle]pathForResource:fileName ofType:@"lrc"];
NSError * error;
NSString * dataStr = [NSString stringWithContentsOfFile:lrcPath encoding:NSUTF8StringEncoding error:&error];
//去掉/r
NSMutableString * tmpStr = [[NSMutableString alloc]init];
NSArray * tmpArray = [dataStr componentsSeparatedByString:@"\r"];
for (int i=0; i
[tmpStr appendString:tmpArray[i]];
}
//按照換行符進行字符串分割
NSArray * lrcArray = [tmpStr componentsSeparatedByString:@"\n"];
//數(shù)據(jù)解析并將空數(shù)據(jù)去掉
for (NSString * lrcStr in lrcArray) {
if (lrcStr.length==0) {
continue;
}
//判斷是歌詞數(shù)據(jù)還是文件信息數(shù)據(jù)
unichar c = [lrcStr characterAtIndex:1];
if (c>='0'&&c<='9') {
//是歌詞數(shù)據(jù)
[self getLrcData:lrcStr];
}else{
//是文件信息數(shù)據(jù)
[self getInfoData:lrcStr];
}
}
//進行歌詞數(shù)據(jù)的重新排序
[_lrcArray sortedArrayUsingSelector:@selector(isTimeOlderThanAnother:)];
}
getLrcData:方法的實現(xiàn)如下:
-(void)getLrcData:(NSString *)lrcStr{
//按照]進行分割
NSArray * arr = [lrcStr componentsSeparatedByString:@"]"];
//解析時間 同一行歌詞可能對應多個時間 最后一個元素是歌詞
for (int i=0; i
//去掉[號
NSString *timeStr = [arr[i] substringFromIndex:1];
//把時間字符串轉(zhuǎn)換成s為單位
NSArray * timeArr = [timeStr componentsSeparatedByString:@":"];
float min = [timeArr[0] floatValue];
float sec = [timeArr[1] floatValue];
//創(chuàng)建模型
LRCItem * item = [[LRCItem alloc]init];
item.time=min*60+sec;
item.lrc = [arr lastObject];
[_lrcArray addObject:item];
}
}
getInfoData:方法的實現(xiàn)如下:
-(void)getInfoData:(NSString *)lrcStr{
NSArray * arr = [lrcStr componentsSeparatedByString:@":"];
//獲取內(nèi)容長度 帶]符號
NSInteger len = [arr[1] length];
if ([arr[0] isEqualToString:@"[ti"]) {
_title = [arr[1] substringToIndex:len-1];
}else if ([arr[0] isEqualToString:@"[ar"]){
_author = [arr[1] substringToIndex:len-1];
}else if ([arr[0] isEqualToString:@"[al"]){
_albume = [arr[1] substringToIndex:len-1];
}
}
實現(xiàn)LRCEngine.h中聲明的getCurrentLRCInLRCArray:atTime:方法如下:
-(void)getCurrentLRCInLRCArray:(void (^)(NSArray *, int))handle atTime:(float)time{
if (!_lrcArray.count) {
handle(nil,0);
}
//找到第一個時間大于time的歌詞位置
int index = -2;
for (int i=0; i<_lrcArray.count; i++) {
float lrcTime = [_lrcArray[i] time];
if (lrcTime>time) {
index=i-1;
break;
}
}
if (index==-1) {
//第一條數(shù)據(jù)
index=0;
}else if (index==-2){
//沒有更大的時間了 最后一條數(shù)據(jù)
index=(int)_lrcArray.count-1;
}
handle(_lrcArray,index);
}
為了驗證LRC歌詞引擎是否正常工作,在ViewController.m文件中引入LRCEngine類的頭文件并在viewDidLoad方法中編寫如下代碼:
- (void)viewDidLoad {
[super viewDidLoad];
LRCEngine * engine = [[LRCEngine alloc]initWithFile:@"匆匆那年"];
[engine getCurrentLRCInLRCArray:^(NSArray *lrcArray, int currentIndex) {
if (lrcArray) {
NSLog(@"%@\n=======\n%@",lrcArray,[lrcArray[currentIndex] lrc]);
}
} atTime:100];
}
上面的代碼中獲取到歌詞文件《匆匆那年》第100秒時的歌詞,打印結(jié)果如圖5-31所示,則說明LRC歌詞引擎工作順利正常。
……