質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

1回答

5214閲覧

TableViewに貼り付けたスイッチのインデックスを取得する方法

Robokun

総合スコア53

iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

0クリップ

投稿2016/10/21 17:59

編集2016/10/21 23:16

Swift3を使ってデータベースと連携したTableViewのコードについて質問です。

データベースからTableViewに貼り付けたスイッチの動作について質問です。
カスタムセルを使い、データベースの内容を表示する事、データを追加、削除はできました。

問題はセルに配置したスイッチを切り替えた時にBool値のデータを切り替えたいのですが
上手くいきません。インターネットでやり方を検索して実装したのですがイマイチ自信がありません。
今出ているエラーメッセージは

**unrecognized selector sent to instance **
というものです。

そもそも、実装に関するロジックなのですが、
テーブルビューのスイッチが押されたという事をどこで判別するかという点ですが
InputViewControllerのスイッチが押されたアクションで取得なのかな?と考えました。
カスタムセルとInput用のビューコレクターのコードは以下になります。

InputViewController

1 2import UIKit 3import RealmSwift 4 5class InputViewController: UIViewController ,UITableViewDelegate, UITableViewDataSource{ 6 7 //OUTLET 8 @IBOutlet weak var pareText: UITextField! 9 @IBOutlet weak var tableView: UITableView! 10 11 //デフォルトのRealmインスタンスを取得する 12 let realm = try! Realm() 13 14 //DB内のデータを保持する配列(IDの順番でソート) 15 let dataArray = try! Realm().objects(Pare.self).sorted(byProperty: "id", ascending: true) 16 17 //データを追加するアクション 18 @IBAction func appPare(_ sender: UIButton) { 19 20 //入力チェック 21 if isValidateInputContents() == false{ 22 print("入力値に問題あり") 23 return 24 } 25 26 //登録するデータを作成 27 let pare = Pare() 28 pare.name = pareText.text! 29 pare.isUse = true 30 if(dataArray.count != 0){ 31 pare.id = dataArray.max(ofProperty: "id")! + 1 32 } 33 34 //Realmに書き込み 35 do { 36 try realm.write { 37 realm.add(pare, update: true) 38 } 39 } catch { 40 print("データ登録失敗") 41 } 42 tableView.reloadData() 43 } 44 45 override func viewDidLoad() { 46 super.viewDidLoad() 47 } 48 49 override func didReceiveMemoryWarning() { 50 super.didReceiveMemoryWarning() 51 } 52 53 // MARK: UITableViewDataSource プロトコルのメソッド 54 //各セクションのセル数を返す 55 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 56 return dataArray.count 57 } 58 59 //各セルの内容を返す 60 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 61 //再利用可能なCellを得る 62 //let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.subtitle, reuseIdentifier: "Cell") 63 let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath) as! CustomTableViewCell 64 65 //Cellに値を設定する 66 let object = dataArray[indexPath.row] 67 cell.setCell(idLabelText: "\(object.id)", tpareLabelText: object.name, swIsUseValue: object.isUse) 68 return cell 69 } 70 71 //セルが選択された時に呼ばれるデリゲートメソッド 72 func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 73 print("セル番号:\(indexPath.row) セルの内容:\(dataArray[indexPath.row])") 74 } 75 76 //セルの削除 77 //セルが削除可能なことを伝える 78 func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCellEditingStyle { 79 return UITableViewCellEditingStyle.delete; 80 } 81 82 //Deleteボタンが押された時データベース削除の処理 83 func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) { 84 if editingStyle == UITableViewCellEditingStyle.delete { 85 try! realm.write { 86 self.realm.delete(self.dataArray[indexPath.row]) 87 tableView.deleteRows(at: [indexPath], with: UITableViewRowAnimation.fade) 88 } 89 } 90 } 91 92 //カスタムセルのスイッチが押された時の処理 93 @IBAction func isUseSwitch(_ sender: UISwitch) { 94 let point = self.tableView.convert(sender.frame.origin, from: sender.superview) 95 if let indexPath = self.tableView.indexPathForRow(at: point) { 96 print("section: \(indexPath.section) - row: \(indexPath.row)") 97 } 98 } 99 100 //データベースの値をチェック 101 private func isValidateInputContents()->Bool{ 102 //名前の入力 103 if let name = pareText.text { 104 if name.characters.count == 0{ 105 return false 106 } 107 }else{ 108 return false 109 } 110 return true 111 } 112} 113

CustomTableViewCellでBool値の物にボタンを割り当ててます

CustomTableViewCell.swift

1import UIKit 2 3class CustomTableViewCell: UITableViewCell { 4 ///OUTLET 5 @IBOutlet weak var idLabel: UILabel! 6 @IBOutlet weak var pareLabel: UILabel! 7 @IBOutlet weak var swIsUse: UISwitch! 8 9 override func awakeFromNib() { 10 super.awakeFromNib() 11 // Initialization code 12 } 13 14 override func setSelected(_ selected: Bool, animated: Bool) { 15 super.setSelected(selected, animated: animated) 16 } 17 18 //セルを設定するメソッド 19 func setCell(idLabelText: String, tpareLabelText: String, swIsUseValue: Bool) { 20 idLabel.text = idLabelText 21 pareLabel.text = tpareLabelText 22 swIsUse.isOn = swIsUseValue 23 } 24}

少し分かりにくい質問になりましたが、実装方法について
解決方法を知りたいと思ってます。
<補足します>
テスト中の画像を載せます

イメージ説明

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

あまりViewController自体でcellのイベント受けることはやらないですが、今の実装でスイッチの切り替えによりCellのindexPathが必要ならUISwitchのサブクラスを作成してcellのindexPathを保持するプロパティを追加すれば良いと思います。
※ コードは最低限で書いています(動確済)

swift

1import UIKit 2 3// ----- ViewController ----- 4 5class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { 6 7 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 8 return 5 9 } 10 11 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 12 let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath as IndexPath) as! CustomTableViewCell 13 14 cell.swIsUse.cellIndexPath = indexPath 15 return cell 16 } 17 18 @IBAction func isUseSwitch(_ sender: CustomSwitch) { 19 print(sender.cellIndexPath) 20 } 21} 22 23// ----- Custom Switch ----- 24 25class CustomSwitch: UISwitch { 26 var cellIndexPath: IndexPath! 27} 28 29// ----- Custom Cell ----- 30 31class CustomTableViewCell: UITableViewCell { 32 @IBOutlet weak var swIsUse: CustomSwitch! 33}

テーブルビューのスイッチが押されたという事をどこで判別するかという点ですが

InputViewControllerのスイッチが押されたアクションで取得なのかな?

カスタムセルに乗っているSwitchのイベントなので以下の様にセルで受けるのが一般的かと思います。
Switchを変更した時にやりたいことがわからないので、とりあえずスイッチをON→OFF,OFF→ONを変更してViewControllerのモデルのSwitchのtrue,falseを書き換えることをやっています。

swift

1 2import UIKit 3 4// ----- ViewController ----- 5 6class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { 7 8 @IBOutlet weak var tableView: UITableView! 9 private var dataArray: Array<CellObject> = [] 10 11 override func viewDidLoad() { 12 super.viewDidLoad() 13 14 createCellObject() 15 } 16 17 func createCellObject() { 18 dataArray.append(CellObject(title: "title1", isSelect: true)) 19 dataArray.append(CellObject(title: "title2", isSelect: false)) 20 dataArray.append(CellObject(title: "title3", isSelect: true)) 21 dataArray.append(CellObject(title: "title4", isSelect: false)) 22 } 23 24 25 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 26 return dataArray.count 27 } 28 29 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 30 let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath as IndexPath) as! CustomTableViewCell 31 cell.cellObject = dataArray[indexPath.row] 32 return cell 33 } 34} 35 36// ----- Model Calss ----- 37 38class CellObject { 39 var title: String! 40 var isSelectSwtch: Bool! 41 42 init(title: String, isSelect: Bool = false) { 43 self.title = title 44 self.isSelectSwtch = isSelect 45 } 46} 47 48 49 50// ----- Custom Cell ----- 51 52class CustomTableViewCell: UITableViewCell { 53 54 @IBOutlet weak var cellSwitch: UISwitch! 55 @IBOutlet weak var titleLabel: UILabel! 56 57 var cellObject: CellObject! { 58 didSet { 59 titleLabel?.text = cellObject.title 60 cellSwitch.isOn = cellObject.isSelectSwtch 61 } 62 } 63 64 @IBAction func changeSwitch(_ sender: UISwitch) { 65 66 cellSwitch.isOn = !cellSwitch.isOn 67 cellObject.isSelectSwtch = cellSwitch.isOn 68 } 69}

回答追記

Delegateを使用してセルのボタンが変更された時に、データを変更して戻しています。

swift

1import UIKit 2 3// ----- ViewController ----- 4 5class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, CustomTableViewCellDelegate { 6 7 @IBOutlet weak var tableView: UITableView! 8 private var dataArray: Array<CellObject> = [] 9 10 override func viewDidLoad() { 11 super.viewDidLoad() 12 13 createCellObject() 14 } 15 16 func createCellObject() { 17 dataArray.append(CellObject(title: "title1", isSelect: true)) 18 dataArray.append(CellObject(title: "title2", isSelect: false)) 19 dataArray.append(CellObject(title: "title3", isSelect: true)) 20 dataArray.append(CellObject(title: "title4", isSelect: false)) 21 } 22 23 24 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 25 return dataArray.count 26 } 27 28 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 29 let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath as IndexPath) as! CustomTableViewCell 30 cell.cellObject = dataArray[indexPath.row] 31 cell.delegate = self 32 return cell 33 } 34 35 func updateCellObject(object: CellObject) { 36 37 dump(object) 38 // スイッチの状態が変更されたデータが渡されてくるのでRealmに保存 39 } 40} 41 42// ----- Model Calss ----- 43 44class CellObject { 45 var title: String! 46 var isSelectSwtch: Bool! 47 48 init(title: String, isSelect: Bool = false) { 49 self.title = title 50 self.isSelectSwtch = isSelect 51 } 52} 53 54 55 56// ----- Custom Cell ----- 57 58protocol CustomTableViewCellDelegate: class { 59 func updateCellObject(object: CellObject) 60} 61 62class CustomTableViewCell: UITableViewCell { 63 64 @IBOutlet weak var cellSwitch: UISwitch! 65 @IBOutlet weak var titleLabel: UILabel! 66 67 weak var delegate: CustomTableViewCellDelegate! 68 69 var cellObject: CellObject! { 70 didSet { 71 titleLabel?.text = cellObject.title 72 cellSwitch.isOn = cellObject.isSelectSwtch 73 } 74 } 75 76 @IBAction func changeSwitch(_ sender: UISwitch) { 77 78 cellSwitch.isOn = !cellSwitch.isOn 79 cellObject.isSelectSwtch = cellSwitch.isOn 80 81 // DelegateでViewControllerに処理を渡す 82 delegate?.updateCellObject(object: cellObject) 83 } 84} 85

投稿2016/10/21 22:38

編集2016/10/21 23:36
_Kentarou

総合スコア8490

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Robokun

2016/10/21 23:14

回答ありがとうございます 補足します。 やりたいことはRealmのデータベースのデータを表示し、そこに表示されているBool値を変更したいということです。 スイッチが押されたタイミングでデータベースにアクセスし、データベース本体のBool値をチェンジしたいと思ってます。 データベースにアクセスするためにプライマリー値であるIDの値が必要と思ってます。 テストしている画像を付けます
_Kentarou

2016/10/21 23:38

回答に追記しました、後はご自身のコードに合わせて適時修正してください。 各セルのデータをセルに渡して、スイッチの変更をデータにもに反映してViewControllerに戻しています。 ViewController側ではそれを保存すれば良いだけだと思います。
Robokun

2016/10/22 14:45

ご返事ありがとうございます。 分かりやすい解説で本当に助かりました。 私の環境では cellSwitch.isOn = !cellSwitch.isOn cellObject.isSelectSwtch = cellSwitch.isOn この部分でデータベースのプライマリーキーが重複するというエラーが出るので この部分は削除し、あくまでカスタムセルは値を渡すだけにして、データベスの更新処理は ViewController で処理するという事でやっと実装できました。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問