茶漬けと玉子焼き

swiftとrubyの教室

【Swift】Fabricを使ってTwitterクライアントアプリを作ってみる 〜その2〜

この記事は以下の記事の続きとなっております。

o-tyazuke.hatenablog.com

今回行ったことは

  • ナビゲーションコントローラの追加
  • ログインボタンを作る
  • タイムラインを取得
  • タイムラインの表示

となります!それでは張り切って行きましょー!!


ナビゲーションコントローラの追加

Twitterでログイン後、タイムラインを表示するViewに画面遷移するため、あらかじめナビゲーションコントローラを追加しておきます。


ログインボタンを作る

ログインボタンを作るには、TWTRLogInButton というクラスがあるので、これを使って実装します。

import UIKit
import TwitterKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        self.navigationItem.title = "login"
        let logInButton = TWTRLogInButton { (session, error) in
            if let unwrappedSession = session {
                let alert = UIAlertController(title: "Logged In",
                                              message: "User \(unwrappedSession.userName) has logged in",
                    preferredStyle: UIAlertControllerStyle.alert
                )
                alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
                self.presentViewController(alert, animated: true, completion: nil)
            } else {
                NSLog("Login error: %@", error!.localizedDescription);
            }
        }   
        logInButton.center = self.view.center
        self.view.addSubview(logInButton)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

ここで、ログイン成功時にセッションを返してくれるので、今後このセッションから、ユーザID等を取得し、タイムラインを表示して行きます。

f:id:biwako_no_otyazuke:20161123030935p:plain:w300


タイムラインを取得

TWTRAPIClient というクラスでリクエストを作成するのですが、インスタンス生成時にTwitterのユーザIDを渡す必要があります。 公式ドキュメントは情報が古いんだよな〜。。。

import Foundation
import TwitterKit

// Timelineを取得
class TwitterAPI {
    let baseURL = "https://api.twitter.com"
    let version = "/1.1"
    
    init() {
        
    }
    
    class func getHomeTimeline(user:String?, tweets: @escaping ([TWTRTweet]) -> (), error: @escaping (NSError) -> ()) {
        let client = TWTRAPIClient(userID: user)
        var clientError: NSError?
        let api = TwitterAPI()
        let path = "/statuses/home_timeline.json"
        let endpoint = api.baseURL + api.version + path
        let request:NSURLRequest? = client.urlRequest(withMethod: "GET", url: endpoint, parameters: nil, error: &clientError) as NSURLRequest?
        
        if request != nil {
            client.sendTwitterRequest(request! as URLRequest, completion: {
                response, data, err in
                if err == nil {
                    var jsonError: NSError?
                    let json:AnyObject? = try! JSONSerialization.jsonObject(with: data!) as AnyObject?
                    if let jsonArray = json as? NSArray {
                        tweets(TWTRTweet.tweets(withJSONArray: jsonArray as! [Any]) as! [TWTRTweet])
                    }else{
                        error(err as! NSError)
                    }
                }else{
                    print("request error: \(err)")
                }
            })
        }
    }
}

受け取ったレスポンスをTWTRTweet.tweets(withJSONArray:)でJSONからTWTRTWeetにコンバートできるみたいです。
それでは、TwitterAPIクラスをTimelineViewControllerから利用します。


タイムラインの表示

ViewControllerからTimelineViewControlerへユーザIDを渡し、TimelineViewControlerでTwitterAPIを叩きます。

import UIKit
import TwitterKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        self.navigationItem.title = "login"
        let logInButton = TWTRLogInButton { (session, error) in
            if let unwrappedSession = session {
                let alert = UIAlertController(title: "Logged In",
                                              message: "User \(unwrappedSession.userName) has logged in",
                    preferredStyle: UIAlertControllerStyle.alert
                )
                alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
//                self.present(alert, animated: true, completion: nil)
                self.performSegue(withIdentifier: "timeline", sender: session)
            } else {
                NSLog("Login error: %@", error!.localizedDescription);
            }
        }
        
        logInButton.center = self.view.center
        self.view.addSubview(logInButton)
    }
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        let session = sender as? TWTRSession
        let dest = segue.destination as! TimelineViewController
        dest.title = session?.userName
        dest.userId = session?.userID
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


}
import Foundation
import TwitterKit

class TimelineViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
    var tableView: UITableView!
    var tweets: [TWTRTweet] = [] {
        didSet {
            tableView.reloadData()
        }
    }
    var prototypeCell: TWTRTweetTableViewCell?
    var userId: String?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        tableView = UITableView(frame: self.view.bounds)
        tableView.delegate = self
        tableView.dataSource = self
        
        prototypeCell = TWTRTweetTableViewCell(style: .default, reuseIdentifier: "cell")
        
        tableView.register(TWTRTweetTableViewCell.self, forCellReuseIdentifier: "cell")
        self.view.addSubview(tableView)
        
        loadTweets()
    }
    
    func loadTweets(){
        TwitterAPI.getHomeTimeline(user: userId, tweets: {
            twttrs in
            for tweet in twttrs {
                self.tweets.append(tweet)
            }
        }, error: {
            error in
            print(error.localizedDescription)
        })
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return tweets.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! TWTRTweetTableViewCell
        
        let tweet = tweets[indexPath.row]
        cell.configure(with: tweet)
        
        return cell
    }
    
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        let tweet = tweets[indexPath.row]
        
        prototypeCell?.configure(with: tweet)
        
        if let height: CGFloat = TWTRTweetTableViewCell.height(for: tweet, style: .regular, width: self.view.bounds.width, showingActions: true){
            return height
        }else{
            return tableView.estimatedRowHeight
        }
    }
}


ここまでで、タイムラインの表示ができていると思います。
f:id:biwako_no_otyazuke:20161127171148p:plain:w300

Twitterのロゴや画像まで表示できてて、ものすごい便利!!
なんだけど、ドキュメントの情報が古いのはどうにかならないものか。。。笑

ボリュームが多くなってしまいましたが、今回はここまで!
次回はツイート機能を実装しようと思いまーす!

続きはこちら

【Swift】Fabricを使ってTwitterクライアントアプリを作ってみる 〜その3〜 - 食後のSwift ~琵琶湖からコンバンハ~