それでは今回は実際に私が作った(アレンジした)コードを紹介します。
今回作ったTwitterクライアントでは、以下の機能を実装しました。
1. アプリのスタート画面にログインボタンがあり、タップするとログインの処理を行う。
2. ログイン後、タイムラインの表示画面に遷移する。
3. メンションの取得もできる。
4. ログアウトボタンを押すとログアウトする。
それでは作成手順を追っていきます。はじめにFablicをインストールします。
ここがわかりやすく解説してくれています。SDKの導入まで行います。
http://blog.tsumikiinc.com/article/20150313_twitter-fabric.html
次にストーリボードの設定を行います。
View Controllerを2つ追加し、3つのView Controllerに以下の名前をつけます。
・Login View Controller:最初に開く画面。ログインボタンがある。上部にはツールバーがあり、「timeline」「mention」「logout」の3つのボタンが設置されている。
・TimelineViewController:ログイン後遷移する画面。ユーザーのタイムラインが表示される。
・Mention View Controller:mentionボタンをタップすることで遷移する。メンション(@ユーザー名がついたリプライなど)が表示される。
さらにNavigation Controllerを追加します。以下のサイトが参考になります。
http://mushikago.com/i/?p=5082
そして、Login View Controllerにツールバーを置き、「timeline」「mention」「logout」の3つのボタンを設置。
「timeline」「mention」ボタンを右クリックしながらドラッグして、それぞれのView Controllerに接続します。
View Controllerのクラスの設定も忘れないように記述します(クラス名は後述のswiftファイル)。
これで、画面の設定ができました。
以降は機能面のコードを書いていきます。
まず、Login View Controller.swift、TimelineViewController.swift、Mention View Controller.swiftを用意します。さらにもう一つ、TwitterAPI.swiftを作成しました。
それぞれ見ていきます。
TwitterAPI.swift
TimelineViewController.swift、Mention View Controller.swiftで使うタイムライン取得やメンション取得のメソッドを別ファイルに定義します。
APIに関しては公式のドキュメントを参考にすると良いです。
import Foundation
import TwitterKit
class TwitterAPI {
let baseURL = "https://api.twitter.com"
let version = "/1.1"
init() {
}
////////////////////////ここからタイムライン取得////////////////////////
class func getHomeTimeline(user: String?, tweets: [TWTRTweet]->(), error: (NSError) -> ()) {
let api = TwitterAPI()
let client = TWTRAPIClient(userID: user)
var clientError: NSError?
let path = "/statuses/home_timeline.json"
let endpoint = api.baseURL + api.version + path
let request:NSURLRequest? = client.URLRequestWithMethod("GET",
URL: endpoint,
parameters: nil,
error: &clientError)
if request != nil {
client.sendTwitterRequest(request!, completion: {
response, data, err in
if err == nil {
do {
let json: AnyObject? = try NSJSONSerialization.JSONObjectWithData(data!, options: [])
if let jsonArray = json as? NSArray {
tweets(TWTRTweet.tweetsWithJSONArray(jsonArray as [AnyObject]) as! [TWTRTweet])
}
} catch {
print("error")
}
} else {
error(err!)
}
})
}
}
class func getMention(user: String?, tweets: [TWTRTweet]->(), error: (NSError) -> ()) {
let api = TwitterAPI()
let client = TWTRAPIClient(userID: user)
var clientError: NSError?
////////////////////////ここまでタイムライン取得////////////////////////
////////////////////////ここからメンション取得////////////////////////
let path = "/statuses/mentions_timeline.json"
let endpoint = api.baseURL + api.version + path
let request:NSURLRequest? = client.URLRequestWithMethod("GET",
URL: endpoint,
parameters: nil,
error: &clientError)
if request != nil {
client.sendTwitterRequest(request!, completion: {
response, data, err in
if err == nil {
do {
let json: AnyObject? = try NSJSONSerialization.JSONObjectWithData(data!, options: [])
if let jsonArray = json as? NSArray {
tweets(TWTRTweet.tweetsWithJSONArray(jsonArray as [AnyObject]) as! [TWTRTweet])
}
} catch {
print("error")
}
} else {
error(err!)
}
})
}
}
}
////////////////////////ここまでメンション取得////////////////////////
Login View Controller.swift
import UIKit
import TwitterKit
class LoginViewController: UIViewController {
var ses: String?
@IBOutlet weak var mention: UIBarButtonItem!
@IBAction func logout(sender: AnyObject) {
if self.ses != nil {
Twitter.sharedInstance().sessionStore.logOutUserID(self.ses!)
let alert = UIAlertController(title: "Logout",
message: "Logout!",
preferredStyle: UIAlertControllerStyle.Alert
)
alert.addAction(UIAlertAction(title: "Logout", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
self.ses = nil
print(self.ses)
} else {
let alert = UIAlertController(title: "yet",
message: "You have not logged in",
preferredStyle: UIAlertControllerStyle.Alert
)
alert.addAction(UIAlertAction(title: "yet", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
}
}
override func viewDidLoad() {
super.viewDidLoad()
let logInButton = TWTRLogInButton { (session, error) in
if session != nil {
self.ses = session?.userID
self.performSegueWithIdentifier("main", sender: session!.userName)
} else {
NSLog("Login error: %@", error!.localizedDescription);
}
}
logInButton.center = self.view.center
self.view.addSubview(logInButton)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if self.ses != nil {
if segue.identifier == "main" {
let dest = segue.destinationViewController as! TimelineViewController
dest.userId = self.ses
}
if segue.identifier == "mention" {
let dest = segue.destinationViewController as! MentionViewController
dest.userId = self.ses
}
} else {
let alert = UIAlertController(title: "yet",
message: "You have not logged in",
preferredStyle: UIAlertControllerStyle.Alert
)
alert.addAction(UIAlertAction(title: "yet", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
}
}
}
LoginViewController.swift
各ボタンがタップされた時の設定をしています。ログインされていない状態でタイムラインの画面に移動しようとした時、ポップアップでログインを要求するようなコメントが出るようにもなっています。
import UIKit
import TwitterKit
class LoginViewController: UIViewController {
var ses: String?
@IBOutlet weak var mention: UIBarButtonItem!
@IBAction func logout(sender: AnyObject) {
if self.ses != nil {
Twitter.sharedInstance().sessionStore.logOutUserID(self.ses!)
let alert = UIAlertController(title: "Logout",
message: "Logout!",
preferredStyle: UIAlertControllerStyle.Alert
)
alert.addAction(UIAlertAction(title: "Logout", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
self.ses = nil
print(self.ses)
} else {
let alert = UIAlertController(title: "yet",
message: "You have not logged in",
preferredStyle: UIAlertControllerStyle.Alert
)
alert.addAction(UIAlertAction(title: "yet", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
}
}
override func viewDidLoad() {
super.viewDidLoad()
let logInButton = TWTRLogInButton { (session, error) in
if session != nil {
self.ses = session?.userID
self.performSegueWithIdentifier("main", sender: session!.userName)
} else {
NSLog("Login error: %@", error!.localizedDescription);
}
}
logInButton.center = self.view.center
self.view.addSubview(logInButton)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if self.ses != nil {
if segue.identifier == "main" {
let dest = segue.destinationViewController as! TimelineViewController
dest.userId = self.ses
}
if segue.identifier == "mention" {
let dest = segue.destinationViewController as! MentionViewController
dest.userId = self.ses
}
} else {
let alert = UIAlertController(title: "yet",
message: "You have not logged in",
preferredStyle: UIAlertControllerStyle.Alert
)
alert.addAction(UIAlertAction(title: "yet", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
}
}
}
TimelineViewController.swift
タイムラインの取得について。実際にAPIを叩くところはTwitterAPI.swiftに書かれているので、ここではAPIを叩いて返ってきた値をセルに埋め込んでいます。
import UIKit
import TwitterKit
class TimelineViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var tableView: UITableView!
var tweets: [TWTRTweet] = [] {
didSet {
tableView.reloadData()
}
}
var prototypeCell: TWTRTweetTableViewCell?
var userId: String?
var userName: 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.registerClass(TWTRTweetTableViewCell.self, forCellReuseIdentifier: "cell")
self.view.addSubview(tableView)
self.view.sendSubviewToBack(tableView)
loadTweets()
}
func loadTweets() {
TwitterAPI.getHomeTimeline(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, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell") as! TWTRTweetTableViewCell
let tweet = tweets[indexPath.row]
cell.configureWithTweet(tweet)
return cell
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
let tweet = tweets[indexPath.row]
prototypeCell?.configureWithTweet(tweet)
let height = TWTRTweetTableViewCell.heightForTweet(tweet,style: .Regular, width: self.view.bounds.width, showingActions: true)
if !height.isNaN {
return height
} else {
return tableView.estimatedRowHeight
}
}
}
Mention View Controller.swift
こちらもTimelineViewController.swift同様です。使うAPIがメンション取得用に変わっただけでほとんどコピペですみました。
import UIKit
import TwitterKit
class MentionViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var tableView: UITableView!
var tweets: [TWTRTweet] = [] {
didSet {
tableView.reloadData()
}
}
var prototypeCell: TWTRTweetTableViewCell?
var userId: String?
var userName: 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.registerClass(TWTRTweetTableViewCell.self, forCellReuseIdentifier: "cell")
self.view.addSubview(tableView)
self.view.sendSubviewToBack(tableView)
loadTweets()
}
func loadTweets() {
TwitterAPI.getMention(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, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell") as! TWTRTweetTableViewCell
let tweet = tweets[indexPath.row]
cell.configureWithTweet(tweet)
return cell
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
let tweet = tweets[indexPath.row]
prototypeCell?.configureWithTweet(tweet)
let height = TWTRTweetTableViewCell.heightForTweet(tweet,style: .Regular, width: self.view.bounds.width, showingActions: true)
if !height.isNaN {
return height
} else {
return tableView.estimatedRowHeight
}
}
}
以上になります。このページの設定を丸々移せば機能するはずです。数ヶ月くらいは有効だと思います…。
エラーが出た時はXcodeの自動修正に任せるのではなく、まずはバージョン変更に伴う設定の変更を確認するのが肝だと学びました。
いろいろ参考になるサイトはあります。これからも丸っと鵜呑みにしてしまうのではなく、教材として活用していきたいです。