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

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

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

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

Q&A

解決済

3回答

540閲覧

TableViewでセルを追加してもindexPathが更新されない

akiraa

総合スコア11

Swift

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

0グッド

0クリップ

投稿2018/03/18 05:21

編集2018/03/19 11:14

前提・実現したいこと

下記のようなTableViewを作成しています
表示上はセルを追加されたように見えてもindexPathが増加していないため
didSelectRowAtのindexPathは常に一番目のデータが帰ってきます
どこがいけないんでしょうか?

発生している問題・エラーメッセージ

セルをタップしても、該当のIndexPathが取得できない

該当のソースコード

Swift

1import UIKit 2import AVFoundation 3import AudioToolbox 4 5class ScannerViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate,UITableViewDelegate,UITableViewDataSource{ 6 7 8 //var itemTable: UITableView? 9 var captureDevice:AVCaptureDevice? 10 var videoPreviewLayer:AVCaptureVideoPreviewLayer? 11 var captureSession:AVCaptureSession? 12 let detectionArea = UIView() 13 var timer: Timer! 14 var counter = 0 15 var tableView: UITableView! 16 //let items = ["Apple","Banana","Orange"] 17 //var barcodeList = [String]() 18 var items = [Item!]() 19 var item: Item! = Item() 20 21 22 override func viewDidLoad() { 23 super.viewDidLoad() 24 25 print("viewDidLoad...") 26 // Do any additional setup after loading the view, typically from a nib. 27 navigationItem.title = "Scanner" 28 view.backgroundColor = .white 29 30 captureDevice = AVCaptureDevice.default(for: .video) 31 // カメラがあるか確認し,取得する 32 if let captureDevice = captureDevice { 33 34 do { 35 let input = try AVCaptureDeviceInput(device: captureDevice) 36 37 captureSession = AVCaptureSession() 38 guard let captureSession = captureSession else { return } 39 captureSession.addInput(input) 40 41 // metadata取得に必要な初期設定 42 let captureMetadataOutput = AVCaptureMetadataOutput() 43 captureSession.addOutput(captureMetadataOutput) 44 45 captureMetadataOutput.setMetadataObjectsDelegate(self, queue: .main) 46 captureMetadataOutput.metadataObjectTypes = [.code128, .qr, .ean13, .ean8, .code39] //AVMetadataObject.ObjectType 47 48 captureSession.startRunning() 49 50 // カメラからの取得映像を画面に表示する 51 videoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession) 52 videoPreviewLayer?.videoGravity = .resizeAspectFill 53 //videoPreviewLayer?.frame = view.layer.bounds 54 videoPreviewLayer?.frame = CGRect(x: 0, y: 0, width: view.frame.size.width, height: view.frame.size.height / 4) 55 view.layer.addSublayer(videoPreviewLayer!) 56 57 } catch { 58 print("Error Device Input") 59 } 60 } //end if let 61 62 view.addSubview(codeLabel) 63 codeLabel.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true 64 codeLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true 65 codeLabel.heightAnchor.constraint(equalToConstant: 50).isActive = true 66 codeLabel.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true 67 68 // どの範囲を解析するか設定する 69 let x: CGFloat = 0.05 70 let y: CGFloat = 0.45 71 let width: CGFloat = 0.9 72 let height: CGFloat = 0.1 73 74 //detectionArea.frame = CGRect(x: view.frame.size.width * x, y: view.frame.size.height * y, width: view.frame.size.width * width, height: view.frame.size.height * height) 75 detectionArea.frame = CGRect(x: (videoPreviewLayer?.frame.width)! * x, y: (videoPreviewLayer?.frame.height)! * y, width: view.frame.size.width * width, height: view.frame.size.height * height) 76 detectionArea.layer.borderColor = UIColor.red.cgColor 77 detectionArea.layer.borderWidth = 3 78 view.addSubview(detectionArea) 79 80 timer = Timer.scheduledTimer(timeInterval: 0.5, target: self, selector: #selector(self.update), userInfo: nil, repeats: true) 81 timer.fire() 82 //self.tableView.register(UINib(nibName: "CustomTableViewCell", bundle: nil), forCellReuseIdentifier: "customCell") 83 self.tableView = { [weak self] in 84 guard let `self` = self else { return UITableView() } 85 //let tableView = UITableView(frame: self.view.bounds, style: .plain) 86 let tableView = UITableView(frame: CGRect(x: 0, y: (videoPreviewLayer?.frame.height)!, width: view.frame.size.width, height: view.frame.size.height - (videoPreviewLayer?.frame.height)!), style: .plain); 87 tableView.autoresizingMask = [ 88 .flexibleWidth, 89 .flexibleHeight 90 ] 91 tableView.delegate = self 92 tableView.dataSource = self 93 94 self.view.addSubview(tableView) 95 96 return tableView 97 }() 98 99 } // end viewDidLoad 100 101 override func didReceiveMemoryWarning() { 102 super.didReceiveMemoryWarning() 103 // Dispose of any resources that can be recreated. 104 } 105 106 override func viewWillAppear(_ animated: Bool) { 107 self.tableView.reloadData() 108 } 109 110 func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) { 111 if metadataObjects.count == 0 { 112 //print("No Input Detected") 113 codeFrame.frame = CGRect.zero 114 codeLabel.text = "No Data" 115 return 116 } 117 print("call metadataOutput") 118 let metadataObject = metadataObjects[0] as! AVMetadataMachineReadableCodeObject 119 120 guard let stringCodeValue = metadataObject.stringValue else { return } 121 counter = 0 122 123 self.item?.title = stringCodeValue 124 self.item?.qty = 1 125 print(self.item!.title as Any) 126 print(self.item!.qty as Any) 127 self.items.append(self.item) 128 129 self.tableView.insertRows(at: [IndexPath(row: 0, section: 0)], with: UITableViewRowAnimation.right) 130 131 guard let barcodeObject = videoPreviewLayer?.transformedMetadataObject(for: metadataObject) else { return } 132 133 // Play system sound with custom mp3 file 134 if let customSoundUrl = Bundle.main.url(forResource: "beep-07", withExtension: "mp3") { 135 var customSoundId: SystemSoundID = 0 136 AudioServicesCreateSystemSoundID(customSoundUrl as CFURL, &customSoundId) 137 //let systemSoundId: SystemSoundID = 1016 // to play apple's built in sound, no need for upper 3 lines 138 139 AudioServicesAddSystemSoundCompletion(customSoundId, nil, nil, { (customSoundId, _) -> Void in 140 AudioServicesDisposeSystemSoundID(customSoundId) 141 }, nil) 142 143 AudioServicesPlaySystemSound(customSoundId) 144 //captureSession?.stopRunning() 145 } 146 147 // Stop capturing and hence stop executing metadataOutput function over and over again 148 print("stop Running") 149 captureSession?.stopRunning() 150 151 // Call the function which performs navigation and pass the code string value we just detected 152 //displayDetailsViewController(scannedCode: stringCodeValue) 153 } 154 155 @objc func update(tm: Timer) { 156 counter += 1 157 //print(counter) 158 if 1 < counter { 159 captureSession?.startRunning() 160 detectionArea.layer.borderColor = UIColor.red.cgColor 161 detectionArea.layer.borderWidth = 3 162 codeLabel.text = "" 163 } 164 } 165 166 func numberOfSections(in tableView: UITableView) -> Int { 167 print("call numberOfSections") 168 return 1 169 } 170 171 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 172 print("items.count (self.items.count)") 173 return self.items.count 174 } 175 176 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 177 178 let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") 179 ?? UITableViewCell(style: .default, reuseIdentifier: "Cell") 180 181 cell.textLabel?.text = self.items[indexPath.row].title 182 183 print("call cellForRowAt") 184 return cell 185 186 } 187 188 func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 189 190 print("Selected! (self.items[indexPath.row].title)") 191 print("indexPath (self.items[indexPath.row])") 192 193 } 194 195 func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { 196 return true 197 } 198 199 func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexpath: IndexPath) { 200 if editingStyle == UITableViewCellEditingStyle.delete { 201 //リストから削除 202 items.remove(at: indexpath.row) 203 204 //セルを削除 205 tableView.deleteRows(at: [indexpath], with: UITableViewRowAnimation.fade) 206 } 207 } 208}

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

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

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

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

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

回答3

0

自分でテーブルにセルを追加してはいけません。
保持している配列にデータを追加した後、テーブルをリロードして下さい。

swift

1self.items.append(self.item) 2//self.tableView.insertRows(at: [IndexPath(row: 0, section: 0)], with: UITableViewRowAnimation.right) 3self.tableView.reloadData()

テーブルの上に追加したいのであれば、配列の先頭にデータを追加して下さい。

swift

1self.items.insert(self.item, at: 0)

投稿2018/03/20 09:02

fuzzball

総合スコア16731

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

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

0

insertRowsの部分を下記のように変更すると何か変わりますでしょうか?

DispatchQueue.main.async { [weak self] in self?.tableView.beginUpdates() // ↓0から変更 self?.tableView.insertRows(at: [IndexPath(row: self.items.count - 1, section: 0)], with: UITableViewRowAnimation.right) self?.tableView.endUpdates() }

投稿2018/03/18 21:54

編集2018/03/19 10:30
newmt

総合スコア1277

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

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

akiraa

2018/03/19 08:56

回答ありがとうございます。 記述してみましたが、状況は変わりませんでした。
newmt

2018/03/19 10:31

一部処理を修正しました。また、self.items.appendの後でprint(self.items)を出力すると何が出力されますでしょうか?
akiraa

2018/03/19 11:31

ご回答ありがとうございます。 printさせると [BarcodeScanner.Item] と表示されます
newmt

2018/03/20 08:25

metadataOutput関数が複数呼ばれた場合にself.itemsには複数アイテムが入っていますでしょうか?また、print(self.item!.title as Any)の中身も教えて頂けましたら幸いです。
akiraa

2018/03/20 12:01

ご回答ありがとうございます。 self.items には同じデーターが複数入ってました print(self.item!.title as Any)ですが [BarcodeScanner.Item, BarcodeScanner.Item] という内容です
guest

0

ベストアンサー

tableView.reloadData()を呼んでいないのでテーブルの更新がされないのではないでしょうか。

【追記】
viewWillAppearでreloadDataを呼んでいるとのことですが、
metadataOutputにviewWillAppearは呼ばれているのでしょうか。
もし呼ばれていてreloadDataが実行されているとしたらself.itemsの中身が変わっていないのかもしれません。

気になったのはクラス変数としてitemを作成していることです。
itemを使いまわしているので、items[0]、items[1]と追加されても常に同じ内容になります。
metadataOutput関数内でしか使用していないので都度生成したほうが良いと考えます。

また、metadataOutput内の以下のコードで関数を抜けていないかなども確認したほうが良いのではないでしょうか。

Swift

1guard let stringCodeValue = metadataObject.stringValue else { return }

投稿2018/03/18 15:31

編集2018/03/20 06:28
nakasho_dev

総合スコア2655

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

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

akiraa

2018/03/19 09:57

ご回答ありがとうございます。 viewWillAppear内にreloadData()を記述してみましたが状況は変わりませんでした。
akiraa

2018/03/20 12:03

ご回答ありがとうございます。 ご指摘いただいた通りitemを局所化したところ一発で解決しました 大変助かりました、ありがとうございます
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問