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

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

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

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

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

Q&A

解決済

1回答

1063閲覧

リストのフリックで削除したい。(xcode )

isekiryu

総合スコア15

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

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

0グッド

0クリップ

投稿2020/09/20 07:16

前提・実現したいこと

録音したファイルを削除できるようにしたいです。

該当のソースコード

ViewContrrler

1// 2// ViewController.swift 3// recordAPP 2 4// 5// Created by user on 2020/09/20. 6// 7 8import UIKit 9import AVFoundation 10 11class ViewController: UIViewController, AVAudioRecorderDelegate, UITableViewDelegate, UITableViewDataSource { 12 13 var recordingSession:AVAudioSession! 14 var audioRecorder:AVAudioRecorder! 15 //録音したものを聴けるようにする。 16 var audioPlayer:AVAudioPlayer! 17 var numberOfRecords:Int = 0 18 19 20 @IBOutlet weak var buttonLabel: UIButton! 21 @IBOutlet weak var myTableView: UITableView! 22 23 // fileprivate func record(at offsets: UITableView) { myTableView.delete(self)} 24 25 @IBAction func record(_ sender: Any) { 26 if audioRecorder == nil { 27 numberOfRecords += 1 28 let filename = getDirectory().appendingPathComponent("(numberOfRecords).m4a") 29 //AVsampleReteKeyは、サンプル 30 let settings = [AVFormatIDKey: Int(kAudioFormatMPEG4AAC), AVSampleRateKey: 12000, AVNumberOfChannelsKey: 1, AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue] 31 32 //start audio recording 33 do { 34 audioRecorder = try AVAudioRecorder(url: filename, settings: settings) 35 audioRecorder.delegate = self 36 audioRecorder.record() 37 buttonLabel.setTitle("□", for: .normal) 38 } catch { 39 displayAlert(title: "Ups!", message: "Recording failed") 40 }} else { 41 //stop audio recording 42 audioRecorder.stop() 43 audioRecorder = nil 44 UserDefaults.standard.set(numberOfRecords, forKey: "myNumber") 45 myTableView.reloadData() 46 buttonLabel.setTitle("○", for: .normal) 47 } 48 } 49 50 51 52 override func viewDidLoad() { 53 super.viewDidLoad() 54 // Do any additional setup after loading the view. 55 //Setting up session 56 myTableView.delegate = self 57 myTableView.dataSource = self 58 59 60 61 recordingSession = AVAudioSession.sharedInstance() 62 if let number:Int = UserDefaults.standard.object(forKey: "myNumber") as? Int 63 { 64 numberOfRecords = number 65 } 66 AVAudioSession.sharedInstance().requestRecordPermission { (hasPermisson) in 67 if hasPermisson { 68 print("ACCEPTED") 69 } 70 } 71} 72 73 74 75 76 77 //Functuon that gets path to directry 78 func getDirectory() -> URL { 79 let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask) 80 let documentDirectory = paths[0] 81 return documentDirectory 82 } 83 //Functuon that displays an alert 84 func displayAlert(title:String, message:String) { 85 let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) 86 alert.addAction(UIAlertAction(title: "dismiss", style: .default, handler: nil)) 87 present(alert, animated: true, completion: nil) 88 } 89 90 //Setting up table view 91func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 92 return numberOfRecords } 93 94 95func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 96 let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) 97 cell.textLabel?.text = String(indexPath.row + 1) 98 return cell } 99 100func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle { 101 return .delete } 102 103func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath:IndexPath) { 104 if editingStyle == .delete { 105 tableView.beginUpdates() 106 107 108 ** _____.remove(at: indexPath.row) ** 109 110 tableView.deleteRows(at: [indexPath], with: .fade) 111 tableView.endUpdates() 112 } 113 } 114 115//録音したものを聴けるようにする。 116func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 117 let path = getDirectory().appendingPathComponent("(indexPath.row + 1).m4a") 118 do{ 119 audioPlayer = try AVAudioPlayer(contentsOf: path) 120 audioPlayer.play() 121 } catch { 122 123 } 124 } 125 } 126 127 128

試したこと

_____.remove(at: indexPath.row) この文字がスクロールで削除できると思うのですが、ファイルがどの文字化がわかっていません。

補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

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

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

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

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

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

guest

回答1

0

ベストアンサー

録音だけだと indexPath.row を基にしたファイル管理に問題はないのですが、削除を考えると不都合が生じるため、UITableView のセルに表示させたり、あるいは再生させるためのファイル名管理を考え直す必要があります。

したがって、

Swift

1 // MARK: - 録音されているファイル名の一覧 2 var fileNames = [URL]()

という感じで、録音されているファイル名のフルパスを保存するための配列を準備し、それを使って削除する操作を行うとやりやすいと思います。

削除部分の考え方は基本的に合っているかと思いますが、コードとしては

Swift

1 // MARK: - 指定したファイルを削除する 2 func deleteFile(filename: URL) -> Bool { 3 do { 4 try FileManager.default.removeItem(at: filename) 5 return true 6 } catch { 7 print(#function, error.localizedDescription) 8 return false 9 } 10 } 11 12 func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath:IndexPath) { 13 if editingStyle == .delete { 14 // MARK: 指定されたファイルをファイルシステムから削除する 15 if deleteFile(filename: fileNames[indexPath.row]) { 16 17 // 最新のファイル一覧を取得し、TableView を再描画 18 fileNames = getFileNames() ?? [] 19 tableView.deleteRows(at: [indexPath], with: .fade) 20 } else { 21 print("削除できませんでした") 22 } 23 } 24 }

といった流れになるかと思います。
上記のコードを見ていただければわかるかと思いますが、指定したファイル名をファイルシステムから削除し、最新のデータを TableView に表示するようにしています。

ちなみに、

Swift

1 fileNames = getFileNames() ?? []

という操作はコード中何度も出てきますので、計算型プロパティにしてしまうのも一つの手かもしれません。

削除操作ができるように辻褄を合わせ、また趣味で勝手にいくつかの機能を付け加えたコードは次のとおりです。

詳しくはコメントをご参照ください。

Swift

1import UIKit 2import AVFoundation 3 4// MARK: - AVAudioPlayerDelegate を追加することで、再生に関する Delegate を呼べるようにする 5class ViewController: UIViewController, AVAudioRecorderDelegate, UITableViewDelegate, UITableViewDataSource, AVAudioPlayerDelegate { 6 7 var recordingSession:AVAudioSession! 8 var audioRecorder:AVAudioRecorder! 9 //録音したものを聴けるようにする。 10 var audioPlayer:AVAudioPlayer! 11 12 // MARK: - 実際に録音されているデータ数 13 //var numberOfRecords = 0 14 var numberOfLastId = 0 15 16 // MARK: - 録音されているファイル名の一覧 17 var fileNames = [URL]() 18 19 @IBOutlet weak var buttonLabel: UIButton! 20 @IBOutlet weak var myTableView: UITableView! 21 22 // fileprivate func record(at offsets: UITableView) { myTableView.delete(self)} 23 24 @IBAction func record(_ sender: Any) { 25 if audioRecorder == nil { 26 numberOfLastId += 1 27 let filename = getDirectory().appendingPathComponent("(numberOfLastId).m4a") 28 29 //AVsampleReteKeyは、サンプル 30 let settings = [AVFormatIDKey: Int(kAudioFormatMPEG4AAC), AVSampleRateKey: 12000, AVNumberOfChannelsKey: 1, AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue] 31 32 //start audio recording 33 do { 34 audioRecorder = try AVAudioRecorder(url: filename, settings: settings) 35 audioRecorder.delegate = self 36 audioRecorder.record() 37 buttonLabel.setTitle("□", for: .normal) 38 } catch { 39 displayAlert(title: "Ups!", message: "Recording failed") 40 } 41 } else { 42 //stop audio recording 43 audioRecorder.stop() 44 audioRecorder = nil 45 UserDefaults.standard.set(numberOfLastId, forKey: "myNumber") 46 47 buttonLabel.setTitle("○", for: .normal) 48 49 // MARK: - 最新の録音情報を取得し、TableView を再描画 50 fileNames = getFileNames() ?? [] 51 52 myTableView.reloadData() 53 } 54 } 55 56 override func viewDidLoad() { 57 super.viewDidLoad() 58 // Do any additional setup after loading the view. 59 //Setting up session 60 myTableView.delegate = self 61 myTableView.dataSource = self 62 63 // MARK: - StoryBoard でプロトタイプセルを作っていれば、次の行は不要 64 myTableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell") 65 66 recordingSession = AVAudioSession.sharedInstance() 67 68 // MARK: - 型キャストしなくとも、Int 型で直接取れる。存在するキーがなければ 0 が代入される 69 numberOfLastId = UserDefaults.standard.integer(forKey: "myNumber") 70 // if let number:Int = UserDefaults.standard.object(forKey: "myNumber") as? Int { 71 // numberOfLastId = number 72 // } 73 74 AVAudioSession.sharedInstance().requestRecordPermission { (hasPermisson) in 75 if hasPermisson { 76 print("ACCEPTED") 77 } 78 } 79 80 // MARK: - 録音されているファイル名の一覧を得る。ファイル名がなければ空配列を入れる。 81 fileNames = getFileNames() ?? [] 82 } 83 84 // MARK: - 指定したファイルを削除する 85 func deleteFile(filename: URL) -> Bool { 86 do { 87 try FileManager.default.removeItem(at: filename) 88 return true 89 } catch { 90 print(#function, error.localizedDescription) 91 return false 92 } 93 } 94 95 // MARK: - 保存されているファイル名一覧を得る処理 96 func getFileNames() -> [URL]? { 97 do { 98 return try FileManager.default.contentsOfDirectory(at: getDirectory(), includingPropertiesForKeys: nil) 99 100 } catch { 101 print(error.localizedDescription) 102 return nil 103 } 104 } 105 106 //Functuon that gets path to directry 107 func getDirectory() -> URL { 108 let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask) 109 let documentDirectory = paths[0] 110 return documentDirectory 111 } 112 113 //Functuon that displays an alert 114 func displayAlert(title:String, message:String) { 115 let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) 116 alert.addAction(UIAlertAction(title: "dismiss", style: .default, handler: nil)) 117 present(alert, animated: true, completion: nil) 118 } 119 120 //Setting up table view 121 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 122 // MARK: - 実際に録音されているファイルの個数を返す 123 //return numberOfLastId 124 return fileNames.count 125 } 126 127 128 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 129 let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) 130 131 // MARK: - 実際に録音されているファイル名を設定する。ラベルにはファイル名だけ表示。 132 //cell.textLabel?.text = String(indexPath.row + 1) 133 cell.textLabel?.text = fileNames[indexPath.row].lastPathComponent 134 135 return cell 136 } 137 138 func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle { 139 return .delete 140 141 } 142 143 func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath:IndexPath) { 144 if editingStyle == .delete { 145 // MARK: 指定されたファイルをファイルシステムから削除する 146 if deleteFile(filename: fileNames[indexPath.row]) { 147 148 // 最新のファイル一覧を取得し、TableView を再描画 149 fileNames = getFileNames() ?? [] 150 tableView.deleteRows(at: [indexPath], with: .fade) 151 } else { 152 print("削除できませんでした") 153 } 154 } 155 } 156 157 //録音したものを聴けるようにする。 158 func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 159 // indexPath.row を基準としてファイル名ではなく、実ファイル名を使う 160 //let path = getDirectory().appendingPathComponent("(indexPath.row + 1).m4a") 161 let path = fileNames[indexPath.row] 162 163 do{ 164 audioPlayer = try AVAudioPlayer(contentsOf: path) 165 166 // MARK: - AVAudioPlayerの delegate を設定する 167 audioPlayer.delegate = self 168 // MARK: - 再生中は他のセルを操作できないようにする 169 myTableView.isUserInteractionEnabled = false 170 171 172 audioPlayer.play() 173 } catch { 174 print(#function, error.localizedDescription) 175 } 176 } 177 178 // MARK: - AVAudioPlayer の delegate 179 func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) { 180 // 再生が終わったら 181 if let indexPath = myTableView.indexPathForSelectedRow { 182 // セルの半単表示を消す 183 myTableView.deselectRow(at: indexPath, animated: true) 184 // 他のセルを選択できるようにする 185 myTableView.isUserInteractionEnabled = true 186 } 187 } 188}

投稿2020/09/20 21:23

TsukubaDepot

総合スコア5086

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

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

isekiryu

2020/09/21 04:34

実行してみたところ、削除できました。完成に向けて頑張っていきたいと思います いつもありがとうございます。お礼をしたいくらいいつも助かっています。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問