【Swift】【Parse】1対多リレーションからデータの抽出（Xcode6 beta5, Parse.com）


# A. 概要
- mBaaSのParseを使用して、テーブル間のリレーションを張る
- 今回はユーザーとツイートを1対多の関係にして、そのユーザーのツイートだけを抽出
- 抽出したデータはUITableViewに表示する

[注] *ViewControllerはVCと表記しています。*

# 1. ユーザーをforeignKeyに持たしてTweetを投稿

まず、Tweetを投稿するためのVCをストーリーボードとCocoa Touch ClassでComposeVC.swiftというファイルを作成します。
次に、ストーリーボード上で、TextFieldとボタンを用意して投稿できる形に整えます。
上記２点が完了したら、ComposeVC.swiftに下記のような関数を追加します。

```ComposeViewController.swift

    @IBOutlet var tweetTextView: UITextView! = UITextView()

    @IBAction func sendTweet(sender: AnyObject) {
        // classの作成。特にmigrationとかを書けなくても下記の一行でテーブルが作成されます。
        var tweet:PFObject = PFObject(className: "Tweets")
        
        // 生成するデータ
        tweet["content"] = tweetTextView.text
        tweet["tweeter"] = PFUser.currentUser()
        
        tweet.saveInBackground()
        
        self.navigationController.popToRootViewControllerAnimated(true)
        
    } 
```

これでcontentとtweeterというカラムが生成されます。（二度目以降は存在するカラムにデータが入るようになります。）
ここで、tweeterというカラムに現在のユーザーのobjectIdを突っ込み、foreignKeyとしてリレーションが張れます。これだけでOK。

あとはストーリーボードから@IBOutletにドラッグでアクションを関連付けます。

# 2. 現在のユーザーのTweetをTableViewで表示する

最初に、ストーリーボードでTableVCを作成し、それと同時に以下の２つファイルを作成する。（Cocoa touch classを選択する）

- MyTimelineTableVC.swift（UITableVC)
- MyTweetTableViewCell.swift（UITableViewCell)

ファイルを作成したら、ストーリーボードでVCのClassをMyTimelineTableVCに変更し、CellのClassをMyTweetTableViewCellに変更する
（Cellのクラスは、ストーリーボードの左下のDocument Outlineからやります）

![スクリーンショット 2014-08-17 21.35.00.png](https://qiita-image-store.s3.amazonaws.com/0/27810/dfb6a320-9a5e-e7ff-c223-9cb1774f3afd.png "スクリーンショット 2014-08-17 21.35.00.png")

次に、MyTweetTableViewCell.swiftを編集します。

```MyTweetTableViewCell.swift
import UIKit

class MyTweetTableViewCell: UITableViewCell {

	// ストーリーボードでtextViewを追加しておいて、下記のIBOutletとひもづける
    @IBOutlet weak var tweetTextView: UITextView! = UITextView()
    
	required override convenience init(style: UITableViewCellStyle, reuseIdentifier: String) {
        self.init(style: style, reuseIdentifier: reuseIdentifier)
        // Initialization code
    }
    
    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

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

        // Configure the view for the selected state
    }

}
```

次に、MyTimelineTableVC.swiftを編集します。

```MyTlimelineTableVC.swift
import UIKit

class MyTimelineTableViewController: UITableViewController {
    
    var timelineData:NSMutableArray = NSMutableArray()
    
    
    required init(coder aDecoder: NSCoder!) {
        super.init(coder: aDecoder)
    }
    
    func loadData(){
        timelineData.removeAllObjects()
        
        // Tweetsテーブルを参照
        var findCurrentUserTweets:PFQuery = PFQuery(className: "Tweets")
		// Tweetsテーブルのtweeterカラムから現在のユーザーのobjectidと一致するデータを抽出
        findCurrentUserTweets.whereKey("tweeter", equalTo: PFUser.currentUser())
        
        findCurrentUserTweets.findObjectsInBackgroundWithBlock{
            (objects:[AnyObject]!, error:NSError!)->Void in
            
            if !error{
                for object in objects{
                    self.timelineData.addObject(object)
                }
                
                let array:NSArray = self.timelineData.reverseObjectEnumerator().allObjects
                self.timelineData = array as NSMutableArray
                
                self.tableView.reloadData()
            }
        }
    }
    
    override func viewDidAppear(animated: Bool) {
        
        self.loadData()
        
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        // Uncomment the following line to preserve selection between presentations
        // self.clearsSelectionOnViewWillAppear = false

        // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
        // self.navigationItem.rightBarButtonItem = self.editButtonItem()
    }

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

    // MARK: - Table view data source

    override func numberOfSectionsInTableView(tableView: UITableView!) -> Int {
        // #warning Potentially incomplete method implementation.
        // Return the number of sections.
        return 1
    }
    
    override func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int {
        // #warning Incomplete method implementation.
        // Return the number of rows in the section.
        // データの数だけrowを返す
        return timelineData.count
    }
    
    
    override func tableView(tableView: UITableView?, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
        let cell:MyTweetTableViewCell = tableView!.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as MyTweetTableViewCell
        
        let tweet:PFObject = self.timelineData.objectAtIndex(indexPath!.row) as PFObject
        
        cell.tweetTextView.text = tweet.objectForKey("content") as String
        
        return cell
    }
}
```

リレーションを使っている部分は下記の２行のみです。

```MyTimelineTableVC.swift
        // Tweetsテーブルを参照
        var findCurrentUserTweets:PFQuery = PFQuery(className: "Tweets")
		// Tweetsテーブルのtweeterカラムから現在のユーザーのobjectidと一致するデータを抽出
        findCurrentUserTweets.whereKey("tweeter", equalTo: PFUser.currentUser())
```

これで通常のタイムラインには全ユーザーのデータが流れて、
マイページには自分のタイムラインのみが流れるようになりました。
（通常のタイムラインに関しては、過去記事を参照してください）

- 通常のタイムライン
![スクリーンショット 2014-08-17 21.43.53.png](https://qiita-image-store.s3.amazonaws.com/0/27810/dfcc3a48-a49d-eaa1-8bbb-c810bfc7b748.png "スクリーンショット 2014-08-17 21.43.53.png")

- マイページのタイムライン
![スクリーンショット 2014-08-17 21.44.11.png](https://qiita-image-store.s3.amazonaws.com/0/27810/bb462f07-8dd8-5906-c03d-2d37b33f81e0.png "スクリーンショット 2014-08-17 21.44.11.png")


# 3. 過去の関連記事
- http://qiita.com/kiiita/items/bc62293f6c4d479993c1
- http://qiita.com/kiiita/items/1a1358437bb702a0af95