##Loginの処理を作ろう
前回作ったTwitterサンプルを利用して、実際のアカウントでログイン処理を実装しよう
こちらが前回作ったもの
これをベースに実際のログイン機能を加えていきます。
##事前に以下の準備しておきましょう
- 第3回授業までのプロジェクト用意
- Twitterアカウント作成
- できればiPhoneの設定からTwitterアカウントを設定
###3回目までの授業プロジェクトを持っていない人は
下記のGitHubのURLからファイルを落としておきましょう。
https://github.com/hayate1996/twitter_sample_03
ファイルのダウンロードは、右下の"Download ZIP"から落とすことができます。
###Twitterアカウントをまだ作ってない人は
Twitterアカウントを持っていない人は、以下の手順で作成しましょう。
Twitterの公式ページへアクセスして、新規作成をクリックします。
新規作成をクリックすると下記の画面があるので、登録するアカウント名や自分のメールアドレスを入力しましょう。
※ 下記は記入例です。
すると、アカウントが作成されて認証用のメールアドレスが届くので認証すれば終わりです。電話番号の入力はスキップできます。
登録が終わったら、レコメンドなどを利用して有名人や友達のアカウントをフォローしておきましょう。
##iPhoneに登録したアカウントを表示・選択しよう
それでは、iPhoneに登録したアカウントのデータ取得をする部分の実装をしていきます。
アカウントのデータ取得は、基本的にプログラムを書いて実装していきます。
アカウントのデータを取得するには、Twitterが提供しているAPIを利用します。APIを利用するために、iOSで提供しているAccountフレームワークとSocialフレームワークの2つをプロジェクトに追加します。
###フレームワーク追加
1: ナビゲーションエリアで一番上に表示されているプロジェクトファイルを選択します。
2: コーディングエリアのタブから"Build Phase"を選択します。
3: コーディングエリアに表示されたリストの"Link Binary With Libraries"の▶︎をクリックして展開します。
4: "+"ボタンからフレームワークを追加します。
5: 検索バーに"Account"と入力してAccount.Frameworkを選択した状態で"Add"をします。
6: すると、"Link Binary With Libraries"にAccount.Frameworkが追加されています。同じ手順でSocial.Frameworkも追加をしましょう。
###コーディング
先ほどプロジェクトに追加したAccountフレームワークをViewControllerで読み込みましょう。読み込むには"import"を使います。
import UIKit
import Accounts // 追加
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
/*
省略
...
*/
}
デバイスに登録したTwitterアカウントを取得して表示するための変数を定義します。accountsListは削除します。
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var accountStore = ACAccountStore() // 追加
var twAccount = ACAccount() // 追加
var accounts = [ACAccount]() // 追加
/*
省略
...
*/
}
viewDidLoadからaccountsListの初期化を削除します。
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
/* 省略 */
// 変更
override func viewDidLoad() {
super.viewDidLoad()
}
/* 省略 */
}
デバイスからTwitterのアカウント情報を読み込んで、アカウントのリストを表示します。
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
/* 省略 */
@IBAction func tappedLoginButton(sender: AnyObject) {
/* 省略 */
}
// 追加
/* iPhoneに設定したTwitterアカウントの情報を取得する */
func getTwitterAccountsFromDevice(){
let accountType = accountStore.accountTypeWithAccountTypeIdentifier(ACAccountTypeIdentifierTwitter)
accountStore.requestAccessToAccountsWithType(accountType, options: nil) { (granted:Bool, aError:NSError?) -> Void in
// アカウント取得に失敗したとき
if let error = aError {
println("Error! - \(error)")
return;
}
// アカウント情報へのアクセス権限がない時
if !granted {
println("Cannot access to account data")
return;
}
// アカウント情報の取得に成功
self.accounts = self.accountStore.accountsWithAccountType(accountType) as! [ACAccount]
self.showAndSelectTwitterAccountWithSelectionSheets()
}
}
/* 省略 */
}
ログインするアカウントを選択した後のタイムライン画面への遷移処理を追加します。
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
/* 省略 */
func selectTwitterAccountsFromDevice(){
/* 省略 */
}
// 追加
/* iPhoneに設定したTwitterアカウントの選択画面を表示する */
func showAndSelectTwitterAccountWithSelectionSheets() {
// アクションシートの設定
var alertController = UIAlertController(title: "Select Account", message: "Please select twitter account", preferredStyle: .ActionSheet)
for account in accounts {
alertController.addAction(UIAlertAction(title: account.username, style: .Default, handler: { (action) -> Void in
// 選択したアカウントをtwAccountに保存
self.twAccount = account
self.performSegueWithIdentifier("segueTimelineViewController", sender: nil)
}))
}
// キャンセルボタンは何もせずにアクションシートを閉じる
let CanceledAction = UIAlertAction(title: "Cancel", style: .Cancel, handler: nil)
alertController.addAction(CanceledAction)
// アクションシート表示
self.presentViewController(alertController, animated: true, completion: nil)
}
}
TimelineViewControllerに選択したアカウントを渡すための処理を追加します。
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
/* 省略 */
/* アカウントを選択したあと、タイムライン画面へ遷移する処理 */
func showAndSelectTwitterAccountWithSelectionSheets(accounts: [ACAccount]) {
/* 省略 */
}
}
Loginボタンを押したときメソッド(tappedLoginButton)の処理を変更します。
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
/* 省略 */
// 変更
@IBAction func tappedLoginButton(sender: AnyObject) {
self.selectTwitterAccountsFromDevice()
}
/* 省略 */
}
それぞれを追加したら、シミュレーターを起動して実行してみましょう。
##解説
####フレームワーク
今回、SocialとAccountの2つのフレームワークを利用してTwitterアカウントとタイムラインの取得を行いました。では、Frameworkとはなんでしょう?
フレームワークとは、特定の機能を使いやすくしたり、必要な機能を提供するプログラムをまとめたものです。SocialとAccountのフレームワークは、Social機能を使いやすくしてくれます。
例えば、マップのフレームワークでは
- "GPSを使って座標を取得する"
- "現在地から目的地へのルートを取得する"
- "取得した座標をマップに表示する"
- "マップのUI"などを提供します。
などを提供して、実装を助けてくれています。
##タイムラインを取得して表示しよう
TimelineViewControllerにタイムラインを取得する処理を追加しましょう。
先ほどプロジェクトに追加したSocialフレームワークをTimelineViewControllerで読み込みましょう。読み込むには"import"を使います。
import UIKit
import Social // 追加
import Accounts // 追加
class TimelineViewController: UITableViewController, UITableViewDelegate, UITableViewDataSource {
let cellIdentifier = "tweetCell"
var tweets = [] // 変更
var twAccount = ACAccount() // 追加
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.title = "Timeline"
fetchTimeline() // 追加
tableView.contentOffset.y = -self.refreshControl!.frame.size.height //追加
// tweetsの初期化は削除
}
/*
省略
...
*/
}
TimelineViewControllerに選択したアカウントを渡すための処理をViewControllerに追加しましょう。
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
/* 省略 */
// TimelineViewControllerを表示する際に選択したアカウントを渡す
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "segueTimelineViewController" {
var vc = segue.destinationViewController as! TimelineViewController
vc.twAccount = self.twAccount
}
}
}
タイムラインを取得するメソッドfetchTimeline()を追加します。
class TimelineViewController: UITableViewController, UITableViewDelegate, UITableViewDataSource {
/* 省略 */
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.performSegueWithIdentifier("showTimelineDetailViewController", sender: nil)
}
// 追加
// Twitter APIを使ってタイムラインを取得しtweetsに保存する
func fetchTimeline() {
let URL = NSURL(string: "https://api.twitter.com/1.1/statuses/home_timeline.json")
let request = SLRequest(forServiceType: SLServiceTypeTwitter, requestMethod: .GET, URL: URL, parameters: nil)
request.account = twAccount
UIApplication.sharedApplication().networkActivityIndicatorVisible = true
request.performRequestWithHandler { (data, response, error:NSError?) -> Void in
UIApplication.sharedApplication().networkActivityIndicatorVisible = false
if error != nil {
println("Fetching Error: \(error)")
return;
}
self.tweets = NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments, error: nil) as! NSArray
dispatch_async(dispatch_get_main_queue(), {
self.tableView.reloadData()
})
}
}
}
tableView:numberOfRowsInSection:メソッドの実装を変更します
class TimelineViewController: UITableViewController, UITableViewDelegate, UITableViewDataSource {
/* 省略 */
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tweets.count // 変更
}
/* 省略 */
}
取得したツイートをセルにセットします。
class TimelineViewController: UITableViewController, UITableViewDelegate, UITableViewDataSource {
/* 省略 */
// 変更
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("tweetCell") as? UITableViewCell
if cell == nil {
cell = UITableViewCell(style: .Default, reuseIdentifier: "tweetCell")
}
// ↓ 変更
let tweet = tweets[indexPath.row] as! Dictionary<String,AnyObject>
let text = tweet["text"] as! String
let user = tweet["user"] as! Dictionary<String,AnyObject>
let name = user["name"] as! String
let image = UIImage(data: NSData(contentsOfURL: NSURL(string: user["profile_image_url"] as! String)!)!)
let aCell = cell!
aCell.imageView?.image = image
aCell.textLabel?.text = text
aCell.detailTextLabel?.text = name
return aCell
}
/* 省略 */
}
##Tips
###UIAlertControllerについて
UIAlertControllerは、アラートはアクションシートを使うために提供されているクラスです。UIKit.Frameworkで提供されています。今回、アカウントの選択画面を実装するのに使用しています。
##まとめ
- フレームワークは特定の機能を使いやすくするプログラムの集まり
- フレームワークを利用するときはプロジェクト設定の"Build Phase"から追加する
- ユーザーごとにタイムラインを表示するために、ユーザー情報を使ってタイムラインを初期化する