[Swift]Music App #3 JSON, Codable, Instagram API

--

Music app的version 2我加上了Instagram的功能,播放音樂的部分則改成透過iTune API播放指定歌手的音樂,透過tab bar controller可以切換Instagram和iTune音樂,這樣一來它就變成能夠追蹤喜愛的歌手的瘋狂粉絲app!

因為看完了Miss Americana非常崇拜才華洋溢人正心也美的Taylor Swift,所以就用她來做練習吧!

JSON

Instagram API

將以下的username替換成欲搜尋的帳號名稱,即可以得到該帳號首頁的JSON資料。

https://www.instagram.com/username/?__a=1

使用Postman來測試API

使用Postman來測試,得到了Taylor Swift Instagram首頁的JSON資料。

仔細觀察,就可以發現我們需要的資料藏在哪裡了。找出以下資料的Key是誰,就可以做出簡易版的Intagram。

帳號資料:使用者帳號、使用者名稱、粉絲人數、追蹤者數量、總貼文數、頭像、狀態
貼文資料:12篇貼文的原始圖片、縮圖、敘述、按讚數、貼文時間

自訂型別IGData

找出了想要使用的資料,在用JSONDecoder將JSON轉換成自訂的型別之前,要先設定好自訂的型別。

原本想偷懶使用quicktype一鍵獲得定義好的struct,但因為資料中太多東西不會使用到,還要一個個檢查修改反而浪費更多時間,所以最後還是按照架構一層一層地設定struct。

我發現像按讚數、追蹤人數這類數字的最底層都叫count,儲存的資料型別皆為Int,所以訂了一個通用的count。

另外也發現每篇貼文的資料是存放在[edges] -> node底下,而貼文的敘述也是edge_media_to_caption -> [edges]-> node -> text,於是就偷懶將edge_media_to_caption底下資料的型別設為[edges]。但因為上層的[edges] -> node底下並沒有名為text的資料,而edge_media_to_caption -> [edges]-> node底下也沒有按讚數、照片url等等資料,所以在此將這些常數的型別都設為optional,以避免轉換型別時找不到對應的資料而出現問題,也避免xcode氣噗噗地跳出recursive value type is not allowed的error。

用JSONDecoder將JSON轉換成Codable的自訂型別

在IGVC中定義獲取資料的func fetchIGData(),使用URLSession來抓取資料。由於URLSession是在background thread執行,因此也設定取得資料後利用DispatchQueue.main.async切換到main thread來update UI元件。

將資料顯示在App上

資料顯示分兩個部分:table view header和table view cell

Table View Header

table view header顯示的是user account的資料。

透過先前宣告的var igData將下載下來的資料撈出來,顯示在UI elements上。

因為以些藝人太紅了,像Taylor粉絲人數超過百萬,IG並不會將這麼長的數字完整顯示在IG上,而是用K、M來代替千、百萬。為了模仿IG的人數顯示方式,我也做了一個func followerNumConverter來調整我的follower label顯示人數的方式。

user頭像在JSON資料中是一串URL,儲存在igData.graphql.user.profile_pic_url_hd中。

在這裡使用URLSession抓取圖片,然後將圖片顯示在pro pic image view上。

Table View Cell

先前宣告了型別為IGData.Graphql.User.Edge_owner_to_timeline_media.Edges的array變數。

var igPosts = [IGData.Graphql.User.Edge_owner_to_timeline_media.Edges]()

在資料下載前,這個array裡的資料數量是0,所以numberOfRowsInSection的數量為0。下載後array中有了抓下來的資料,reloadData重新載入就會顯示array中的資料數。

有了資料以後,也可以顯示在cell中的UI elementss上。

從IG得到的JSON中,時間儲存為10位數的timestamp,透過下列處理後顯示在label上。

let timestamp = post.node.taken_at_timestamp //10位數的timestamp
let postTime = Date(timeIntervalSince1970: timestamp!) //轉換為可讀的時間
let dateFormatter = DateFormatter()
dateFormatter.dateStyle = .long //顯示年、月、日
dateFormatter.timeStyle = .none //不顯示時間
dateFormatter.locale = Locale.current //使用裝置系統顯示日期的語言、格式
let dateString = dateFormatter.string(from: postTime) //將時間以上面設定的格式用string輸出

利用先前宣告的func updateImage(),可以傳入從JSON中得到pro pic URL,以及欲更改的Image View,輕鬆讓Taylor美美的頭像和post image顯示在cell中。

References:

Auto Layout

UITextView

Error Handling

DateFormatter

Instagram API

Postman

JSON & Codable

--

--

Penny Ng
彼得潘的 Swift iOS / Flutter App 開發教室

A passionate self-taught  iOS developer. Write to record my learning and share the knowledge