1
/
5

研修3-4 -iPhoneアプリ作成4-

それでは今回は実際に私が作った(アレンジした)コードを紹介します。

今回作った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の自動修正に任せるのではなく、まずはバージョン変更に伴う設定の変更を確認するのが肝だと学びました。

いろいろ参考になるサイトはあります。これからも丸っと鵜呑みにしてしまうのではなく、教材として活用していきたいです。

株式会社アクシス's job postings
2 Likes
2 Likes

Weekly ranking

Show other rankings
Like Ryota Yamada's Story
Let Ryota Yamada's company know you're interested in their content