[Swift]Parseで簡単 DB連携でTwitter作成

  • 40
    Like
  • 0
    Comment
More than 1 year has passed since last update.

Parseとはなんぞや

バックエンドをswift(Obj-c)だけで簡単に実装できてしまうもの。

ここではざっくり説明していきます。
詳しくはParse iOS Guidをみて下さい。

ParseのDBの接続部分だけ見たい方は目次の[ParseDB連携]で飛んで下さい。

作成するアプリ

Twitterのようなアプリを作成しながら、Parseのありがたさを見ていきます。
メインはParseで用意されているDB(データベース)に保存するところですね。

名称未設定.png

Parse.comに新規登録

まずは、Parse.comに登録します。

登録完了したら、ホーム画面の右上の『Go to your apps』をクリック。

Parse_と_Parseを使ってみよう.png


次の画面では、Parse上にアプリ新しく作ります。その時に、アプリ名を設定します。

Home___Parse.png


作成されたアプリをクリックすると...

Home___Parse.png


アプリの管理ページが登場

Analytics___Parse.png

ここのページで保存したデータなどを確認するわけですねえ。

ここまでで、一旦Parse側の操作は終わりです。

Xcode側で新規プロジェクトを作成

いつものように、Xcodeのプロジェクトを作ります。

SDKのインポート

作成したプロジェクトにParseに用意されている、SDKをインポートします。

Prase.comに戻り、アプリ管理ページの下部の[Downloads]をクリック

Analytics___Parse.png


SDKをクリックすると、SDKをダウンロードすることができます。

Downloads___Changelogs___Parse.png


ダウンロードしたzipファイルを解凍し、その中の以下の2つのファイルをXcodeにドラッグ&ドロップでインポートしましょう。

  • Parse.framework
  • Bolts.framework

その他の必要なフレームワークをインポート

先程の2つのフレームワーク以外に必要なものをインポートします。

以下の画像のように、Linked Frameworks and Libraries まで行き、必要なフレームワークを追加します。

追加するファイル以下のものです。

  • AudioToolbox.framework
  • CFNetwork.framework
  • CoreGraphics.framework
  • CoreLocation.framework
  • MobileCoreServices.framework
  • QuartzCore.framework
  • Security.framework
  • StoreKit.framework
  • SystemConfiguration.framework
  • libsqlite3.dylib
  • libz.dylib

Parseで作成したアプリとXcodeのプロジェクトの紐付け

現段階では、Parse.comで作成したアプリと、Xcodeで作成したプロジェクトは独立しているので、
Parse.comで発行される、keyを用いて紐付けます。

Parse.com

Edit_Your_App___Parse.png

  • Application ID
  • Client Key

この2つを使用します。

Xcodeプロジェクト

AppDelegate.swiftに以下のように編集します。

AppDelegate.swift
import UIKit
import Parse   //Parseをインポート

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

        //Parseで取得した[Application ID]と[Client Key]を指定
        Parse.setApplicationId("[Application ID]", clientKey: "[Client Key]")

        return true
    }

以上の操作で、連携は完了です。

UIの作成と必要なSwiftファイルの追加

Main.storyboard上はざっくりこんな感じです。

Main_storyboard_と_PracticeParseLogin_xcodeproj.png


必要なファイルを作成します。

  • Models
    • Tweet.swift(NSObject)
    • TweetManager.swift(NSObject)
  • Views
    • TweetTableViewCell.swift(UITableViewCell)
    • TweetTableViewCell.xib
  • ViewControllers
    • TweetsTableViewController.swift(UITableViewController)
    • NewTweetViewController.swfit(UIViewController)


今回は、Parseで用意さえたDBとの接続がメインなので、それ以外の部分はざざざっと書いていきます。

Tweet.swft
import UIKit
import Parse

class Tweet: NSObject {
    var name: String!
    var text: String!

    init(name: String, text: String) {
        self.name = name
        self.text = text
    }

    func saveTweet() {
        //後ほどParseのdbに保存する処理を書く
    }
}
TweetManager.swift
import UIKit
import Parse

class TweetManager: NSObject {

    var tweets: Array<Tweet> = []
    static let sharedInstance = TweetManager()

    func fetchTweets(callback: () -> Void) {
        //後ほどParseのdbからツイート情報を取得する処理を記述    
    }
}

TweetTableViewCell.swift
import UIKit

class TweetTableViewCell: UITableViewCell {
    @IBOutlet weak var tweetLabel: UILabel!
    @IBOutlet weak var nameLabel: UILabel!
    @IBOutlet weak var tweetImageView: UIImageView!

    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
        tweetLabel.numberOfLines = 0
        tweetImageView.clipsToBounds = true
        tweetImageView.contentMode = UIViewContentMode.ScaleAspectFill
    }

    override func setSelected(selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }

}

import UIKit

class TweetsTableViewController: UITableViewController {

    let tweetCollection = TweetManager.sharedInstance

    override func viewDidLoad() {
        super.viewDidLoad()

        tableView.registerNib(UINib(nibName: "TweetTableViewCell", bundle: nil), forCellReuseIdentifier: "TweetTableViewCell")
        tableView.estimatedRowHeight = 90
        tableView.rowHeight = UITableViewAutomaticDimension
    }

    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        navigationItem.rightBarButtonItem = UIBarButtonItem(title: "New", style: UIBarButtonItemStyle.Plain, target: self, action: "showNewTweetViewController")
        let callback = { () -> Void in
            self.tableView.reloadData()
        }
        tweetCollection.fetchTweets(callback)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 1
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return tweetCollection.tweets.count
    }

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("TweetTableViewCell", forIndexPath: indexPath) as! TweetTableViewCell
        let tweet = tweetCollection.tweets[indexPath.row]
        cell.tweetImageView.image = UIImage(named: "omoto")
        cell.nameLabel.text = tweet.name
        cell.tweetLabel.text = tweet.text
        return cell
    }

    func showNewTweetViewController() {
        performSegueWithIdentifier("toNewViewController", sender: nil)
    }

    override func preferredStatusBarStyle() -> UIStatusBarStyle {
        return UIStatusBarStyle.LightContent
    }
}

NewTweetViewController.swift
import UIKit

class NewTweetViewController: UIViewController, UITextViewDelegate {

    @IBOutlet weak var placeholderLabel: UILabel!
    @IBOutlet weak var tweetButton: UIButton!
    @IBOutlet weak var tweetTextView: UITextView!
    @IBOutlet weak var nameTextfield: UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()
        tweetTextView.delegate = self
        tweetButton.layer.cornerRadius = 5
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    func textViewShouldBeginEditing(textView: UITextView) -> Bool {
        placeholderLabel.hidden = true
        return true
    }

    func textViewShouldEndEditing(textView: UITextView) -> Bool {
        if textView.text.isEmpty {
            placeholderLabel.hidden = false
        }
        return true
    }

    @IBAction func tapTweetButton(sender: UIButton) {
        if nameTextfield.text.isEmpty || tweetTextView.text.isEmpty {
            println("Name or text is empty")
        } else {
            let tweet = Tweet(name: nameTextfield.text, text: tweetTextView.text)
            tweet.saveTweet()
            navigationController?.popViewControllerAnimated(true)
        }
    }
}

一旦ここまで。

ParseのDB連携

いよいよ今回のメインです。

DBにデータを保存

Tweet.swiftのsaveTweet()を編集していきます。

Tweet.swft
import UIKit
import Parse

class Tweet: NSObject {
    var name: String!
    var text: String!

    init(name: String, text: String) {
        self.name = name
        self.text = text
    }

    func saveTweet() {
        let tweetsObject = PFObject(className: "tweets")
        tweetsObject["name"] = name
        tweetsObject["text"] = text
        tweetsObject.saveInBackgroundWithBlock { (success, error) -> Void in
            if success {
                println("Tweet has been saved")
            }
        }
    }
}

それぞれ解説していきます。

PFObject(className: "tweets")では引数に指定した名前のクラスがParse上に存在すればそのオブジェクトを取得し、無ければ生成してくれます。

tweetsObject["name"] = nameでは、作成したテーブルに name という名前のカラムを作成し、値を保存しています。

最後にsaveInBackgroundWithBlock()メソッドによって、非同期でDBに値を保存します。

DBから値の取得

続いて、保存した値を取得しましょう。TweetManager.swiftのfetchTweets()メソッドを編集します。

TweetManager.swift
import UIKit
import Parse

class TweetManager: NSObject {

    var tweets: Array<Tweet> = []
    static let sharedInstance = TweetManager()

    func fetchTweets(callback: () -> Void) {
        let query = PFQuery(className: "tweets")
        query.orderByDescending("createdAt")
        query.findObjectsInBackgroundWithBlock { (tweets, error) -> Void in
            if error == nil {
                self.tweets = []
                for tweet in tweets as! Array<PFObject> {
                    let name = tweet["name"] as! String
                    let text = tweet["text"] as! String
                    let tweet = Tweet(name: name, text: text)
                    self.tweets.append(tweet)
                }
                callback()
            }
        }    
    }
}


let query = PFQuery(className: "tweets")
DBから作成したオブジェクトを取得するためには、PFQueryを使用しています。

query.orderByDescending("createdAt")
取得した複数のオブジェクトを並び替えています。

findObjectsInBackgroundWithBlock()メソッドにてDBから実際にツイートのデータを全て非同期で取得します。
後は取得すたツイートでデータを作成したTweetモデルに変換し、配列に保存しています。

Parse上で保存したデータの確認

Banners_and_Alerts_と_tweets___Parse.png

ツイートしたデータを確認することができました。


次回予告

次回はParseを使ったログイン機能の実装を紹介しちゃうぞえ