1対多の関係にあるデータの子クラス側にデータを追加保存したい
1対多の親子関係にあるRealmのデータの子クラス側に新たなデータを追加したいです。
新しい親クラスと新しい子クラスの両方を一度に追加する方法はわかりますが、既に存在する親クラスに、新たな子クラスのデータを追加する方法がわかりません。
具体的には、親クラスThreadData
はチャットのスレッド概要(タイトル名、登録者名等)、子クラスThreaadTalkData
にはそのスレッドに対する返信ごとに、その返信内容(返信文章、返信者名等)のデータを追加していきます。ひとつのスレッド概要に、複数の返信データがあるイメージです。
親クラスは、FirstVC
内に情報を入力、ボタンを押すことでRealmにデータが追加され、スレッド概要がFirestV
C内にあるtableView
に表示されます。tableView
のセルをクリックすると、下記ThreadVC
に移動して親クラスのスレッド概要と子クラスの返信データをThreadVC
内にあるtableView
に表示します。
子クラスは、Lineの返信のようにtextField
に返信内容を記入し、投稿ボタンfunc Toko()
を押すと子クラスThreaadTalkData
を親クラスThreadData
と紐付いている新たなデータとして追加、保存したいのですが、その方法がわかりません。
試行錯誤し、下記コードのTreadVC内、func Toko
のように書きましたが、エラーが出ます。(詳細は`func Toko`部分のコメントを参照)
以下、コードの詳細です。
FirstVC
のセル選択によるVC移動部分
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
//delegateを通じて、何を選択したか通知
appDelegate.selectedThreadIndexPath = indexPath.row
let threadViewController = ThreadViewController()
threadViewController.modalTransitionStyle = UIModalTransitionStyle.CoverVertical
self.presentViewController(threadViewController, animated: true, completion: nil)
}
ThreadVC
(一部省略)
import UIKit
import RealmSwift
class ThreadViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UITextFieldDelegate {
var appDelegate: AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
var selectedIndexPath: Int = Int()
var keyboardToolBar = UIToolbar()
var toolbarTextfield: UITextField = UITextField()
var threadTableView: UITableView = UITableView()
let realm = try! Realm()
var threadTalkData: NSObject = NSObject()
var selectedThread = ThreadData()
var selectedThreadTalkData = List<ThreaadTalkData>()
var tableData:[ThreadData4Test] = []
var threadTitle: String = String()
var threadDate: String = String()
var threadName: String = String()//これ、スレッド主の名前
var threadNushiPlayerID: Int = Int()
var threadNushiImageName = "personal_icon@2x.png"//!!playerIDから画像をロードする。
var threadNushiComment = String()
...
var isObserving = false
override func viewDidLoad() {
super.viewDidLoad()
selectedIndexPath = appDelegate.selectedThreadIndexPath
//選択したスレッドの取得
selectedThread = threadCollectionDataSource![selectedIndexPath]
//トークデータ全て取得
threadTalkData = realm.objects(ThreaadTalkData)
selectedThreadTalkData = selectedThread.threadTalkDataList
threadTitle = selectedThread.threadTitle
threadDate = selectedThread.threadDate
threadName = selectedThread.threadSpeaker
threadNushiComment = selectedThread.threadMessage
threadNushiPlayerID = selectedThread.threadSpeakerID
var postThread : ThreadData = ThreadData()
print("\(postThread.threadTalkDataList.count)")
...
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return selectedThreadTalkData.count
}
func toko(sender: UIButton) {
//時間の取得
let now = NSDate()
let formatter = NSDateFormatter()
formatter.dateFormat = "yyyy/MM/dd HH:mm:ss"
let stringNow = formatter.stringFromDate(now)
let realm = try! Realm()
//var postThread : ThreadData = ThreadData()
var postData: ThreaadTalkData = ThreaadTalkData()
postData.postedthreadID = selectedThread.threadID
postData.postNo = selectedThreadTalkData.count //これで、+1される。
//返信したプレイヤーを識別するための番号。PersonalDataのplayerIDと同一
var postPerson = realm.objects(PersonalData).first
postData.postPlayerID = (postPerson?.playerID)!
postData.postDate = stringNow
postData.postMessage = commentTextField.text!
postData.postPlayerName = (postPerson?.playerName)!
postData.postPlayerImage = (postPerson?.playerIconImage)!
//postData.ownerThread = selectedThread
if commentTextField.text == "" {
let alertController = UIAlertController(title: "コメントが未入力です。", message: "コメントを入力しましょう。", preferredStyle: .Alert)
let defaultAction = UIAlertAction(title: "OK", style: .Default, handler: nil)
alertController.addAction(defaultAction)
presentViewController(alertController, animated: true, completion: nil)
} else {
selectedThread.threadTalkDataList.append(postData)
do {
let realm = try! Realm()
let thisThreadData = realm.objects(ThreadData).last!
try realm.write{
thisThreadData.threadTalkDataList = selectedThread.threadTalkDataList
//realm.add(selectedThread)
}
} catch {
print("失敗")
}
//print("\(postThread.threadTalkDataList.count)")
toolbarView.hidden = true
commentTextField.resignFirstResponder()
threadTableView.reloadData()
}
}
//この内容で実行すると、
// *** Terminating app due to uncaught exception 'RLMException', reason: 'Can only add, remove, or create objects in a Realm in a write transaction - call beginWriteTransaction on an RLMRealm instance first.'
// *** First throw call stack:
// となります。
ThreadData
(親データ)
import Foundation
import RealmSwift
class ThreadData: Object {
//threadのID。取得していない新規のスレッドがあったら、取得するための番号
dynamic var threadID = 0
dynamic var threadTitle = ""
dynamic var threadMessage = ""
dynamic var threadSpeaker = ""
//しゃべった人のID名前が変わった際に取得できるように。PersonalDataのplayerIDと同一
dynamic var threadSpeakerID = 0
dynamic var threadDate = ""
let threadTalkDataList = List<ThreaadTalkData>()
//以下は使わない。
//会話の順序付けされるための
//collectionviewの順序付けんのために使うかもしれないので、作成
dynamic var countNumber = 0
dynamic var threadMessageNumber = 0
}
ThreaadTalkData
(子データ)
class ThreaadTalkData: Object {
//アルファフラッグ全体でスレッドを識別するためのID
dynamic var postedthreadID = 0
//返信を投稿した順番付けのためのNo. 0から始まる
dynamic var postNo = 0
//返信したプレイヤーを識別するための番号。PersonalDataのplayerIDと同一
dynamic var postPlayerID = 0
//以下、表示情報
dynamic var postDate = ""
dynamic var postMessage = ""
dynamic var postPlayerName = ""
dynamic var postPlayerImage : NSData? = UIImagePNGRepresentation(UIImage(named: "personal_icon@2x.png")!)!
dynamic var ownerThread: ThreadData?
}