今日は画面を追加して、テキストフィールドやテキストビューに入力したデータをParseに投稿できるようにします。
前回の記事をお読みでない方は、下記記事をご参照ください。
完成イメージ
画面の作成
まず最初にStoryBoardを使用して、画面から作成していきます。
デフォルトで追加されているViewControllerは一旦削除して、新たにTableViewControllerを追加します。
[Editor] - [Embed in] - [Navigation Controller]からNavigation Controllerを設定後、Navigation Controllerを"Is Initial View Controller"に設定します。
また、データを登録(参照)する画面としてViewControllerを追加し、TableViewCellからSegueで遷移できるように"control"キーを押しながらドラッグし接続します。
Segueは、Showで接続します。
一通り画面を作ったら、コードを書いていきます。
[File] - [New] - [File]から"Swift File"を選択し、下記クラスの設定をしてください。
TableViewController
import UIKit
import Parse
import ParseUI
class TableViewController: PFQueryTableViewController {
override init(style: UITableViewStyle, className: String!) {
super.init(style: style, className: className)
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
// Configure the PFQueryTableView
self.parseClassName = "Articles"
self.pullToRefreshEnabled = true
self.paginationEnabled = true
self.objectsPerPage = 30
}
// Define the query that will provide the data for the table view
override func queryForTable() -> PFQuery {
var query = PFQuery(className: "Articles")
query.orderByAscending("createdAt")
return query
}
//override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath, object: PFObject?) -> PFTableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! PFTableViewCell!
if cell == nil {
cell = PFTableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "Cell")
}
// Extract values from the PFObject to display in the table cell
if let title = object?["title"] as? String {
cell.textLabel?.text = title
}
if let body = object?["body"] as? String {
cell.detailTextLabel?.text = body
}
if let user_id = object?["user_id"] as? String {
cell.detailTextLabel?.text = user_id
}
return cell
}
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using [segue destinationViewController].
var detailScene = segue.destinationViewController as! DetailViewController
// Pass the selected object to the destination view controller.
if let indexPath = self.tableView.indexPathForSelectedRow() {
let row = Int(indexPath.row)
detailScene.currentObject = (objects?[row] as? PFObject)
}
}
override func viewDidAppear(animated: Bool) {
// Refresh the table to ensure any data changes are displayed
tableView.reloadData()
}
}
設定する部品(コントローラ)を選択してから、Identity Inspectorに表示されいるClassを設定します。
DetailViewController
import UIKit
import Parse
import ParseUI
import Bolts
class DetailViewController: UIViewController{
@IBOutlet weak var article_title: UITextField!
@IBOutlet weak var body: UITextView!
// Container to store the view table selected object
var currentObject : PFObject?
@IBAction func saveButton(sender: UIBarButtonItem) {
if let updateObject = currentObject as PFObject? {
// Update the existing parse object
updateObject["title"] = article_title.text
updateObject["body"] = body.text
// Save the data back to the server in a background task
updateObject.saveEventually()
}else {
// Create a new parse object
var updateObject = PFObject(className:"Articles")
updateObject["title"] = article_title.text
updateObject["body"] = body.text
// Save the data back to the server in a background task
updateObject.saveEventually()
}
// Return to table view
self.navigationController?.popViewControllerAnimated(true)
}
override func viewDidLoad() {
// Unwrap the current object object
if let object = currentObject {
article_title.text = object["title"] as! String
body.text = object["body"] as! String
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
TableViewControllerと同様にクラスを作成し、StoryBoardでクラスの設定を行います。
上記以外に、TableViewで使用するCellの設定が必要で、ClassとStyle、Identifierを以下のように設定します。
テストデータの作成
クラス名を変更したらWebブラウザからParseの管理画面を開き、テストデータを登録します。
最初に、SQLでいうところのテーブルにあたるクラスを作成してください。
今回は、簡易的なブログを想定しているため、"Articles"と命名しました。
次に、カラムを追加します。タイトルを表す"title"と本文を表す"body"を追加します。
定義ができたら、実際にそれらしいデータをエクセルのように入力しておいてください。
ここまでできたら、プログラムを実行します。
上記のようにParseのDBのデータが表示されましたでしょうか?
登録(編集)画面の作成
データを登録したり、編集したりできるように、DetailViewControllerにTextFieldとTextViewを追加し、プログラムから操作できるようControlで接続します。
各部品は、画面右下のObject Libraryから追加できます。
ただ追加しただけでは、各デバイスでのレイアウトが崩れてしまうため、制約(Constraints)を追加してやる必要があります。が、ここではその説明は長くなるため割愛させていただきます。
各オブジェクトが配置できたら、コードからプロパティとして扱えるようにConnectします。Connectには大きく2つがあります。
- Outlet:プロパティとして扱う
- Action:タップされた場合など、予め紐付けたメソッドを呼び出す
上図のように、アシスタントエディアモードにして、"control"キーを押しながらプロパティを定義するあたりにドラッグしてやります。NavigationBarには、データを保存するようの"Save"ボタンを追加し、空の状態でDetailViewを表示するaddメソッドを実装します。(既に紹介したコードには、addメソッド実装済み)
また、バックグラウンドでデータ保存を行えるようにするために、フレームワークBoltsもインポートしておきます。
完成
だいぶ長くなってしまいましたが、これで冒頭で紹介した完成イメージのように動作するはずです。
いかがでしたでしょうか。Parseの使い方、iOSアプリケーションの開発の流れを掴んでいただけたら幸いです。
書ききれていない部分もあるので、詳細はGitのコードを見てみてください。
次回は、ログイン機能を構築してみます。
初歩的なエラーにハマった話(余談)
DetailViewControllerの"Title"プロパティ追加時に、下記エラーが発生
- Cannot override strong property with weak property
- Property 'title' with type 'UITextField!' cannot override a property with type 'String?'
- Getter for 'title' with Objective-C selector 'title' conflicts with getter for 'title' from superclass 'UIViewController' with the same Objective-C selector
- Setter for 'title' with Objective-C selector 'setTitle:' conflicts with setter for 'title' from superclass 'UIViewController' with the same Objective-C selector
原因:UIViewControllerの"title"プロパティと被っていたためでした。
参考:iOS Developer Library - UIKit Framework Reference - UIViewController Class Reference
GitHub
https://github.com/kazuyatamakoshi/ParseSample01