Swift 4: кнопка запускает то же действие в другом UITableViewCell
У меня есть ячейка с 2 кнопками (для прослушивания и распознавания речи), надписью и текстовым полем. Я пытаюсь добиться того, чтобы при нажатии кнопки распознавания речи пользователь произносил содержимое, отображаемое в метке. Моя проблема с этим заключается в том, что кнопка прослушивания работает нормально в соответствии с indexPath.row, а говорящая кнопка - нет. Когда он активен, кнопка в другой ячейке тоже становится активной. И это записывает то же самое в тех клетках.
Вы можете увидеть картину того, о чем я говорю здесь
Методы для прослушивания (то есть синтезатора звука) и распознавания речи находятся в UITableViewCell. Я перепробовал все решения, которые смог найти в Интернете, но ни одно из них не сработало. Пытался
protocol RepeatCellDelegate: class {
func buttonTapped(cell: RepeatCell)
}
но проблема остается той же. Кроме того, я создал еще один проект, и вместо того, чтобы использовать кнопку для распознавания речи, я просто использовал прямой ввод textField, но все равно возникает та же проблема.
Кнопка в классе TableViewCell:
@IBAction func speakButtonPressed(_ sender: Any) {
self.delegate?.buttonTapped(cell: self)
}
мой cellForRowAt indexPath
:
let cell = tableView.dequeueReusableCell(withIdentifier: "RepeatCell") as! RepeatCell
cell.delegate = self
cell.conditionlabel.text = repeatTask[indexPath.row].conditionLabel
return cell
Функция buttonTapped, которая определяет индекс ячейки и записывает речевой ввод. После нажатия кнопки печатается индекс правой ячейки, но действие запускается и в другой ячейке.
func buttonTapped(cell: RepeatCell) {
guard let indexPath = self.repeatTV.indexPath(for: cell) else {
return
}
cell.speakButton.isSelected = !cell.speakButton.isSelected
if (cell.speakButton.isSelected){
self.recordAndRecognizeSpeech()
} else {
audioEngine.inputNode.removeTap(onBus: 0)
recognitionTask?.cancel()
}
print("Button tapped on row \(indexPath.row)")
}
// функция распознавания речевого ввода:
// variables for speech recognizer
let audioEngine = AVAudioEngine () let speechRecognizer: SFSpeechRecognizer? = SFSpeechRecognizer (locale: Locale.init (идентификатор: "en-US"))) let request = SFSpeechAudioBufferRecognitionRequest() var распознавание Task: SFSpeechRecognitionTask?
// речевая функция func recordAndRecognizeSpeech () {
let node = audioEngine.inputNode
let recordingFormat = node.outputFormat(forBus: 0)
node.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { buffer, _ in
self.request.append(buffer)
}
audioEngine.prepare()
do {
try audioEngine.start()
} catch {
return print(error)
}
guard let myRecognizer = SFSpeechRecognizer() else {
return
}
if !myRecognizer.isAvailable {
return
}
recognitionTask = speechRecognizer?.recognitionTask(with: request, resultHandler: { (result, error) in
if result != nil { //
if let result = result{
let cell = self.repeatTV.dequeueReusableCell(withIdentifier: "RepeatCell") as! RepeatCell
let bestString = result.bestTranscription.formattedString
if cell.speakButton.isSelected == true {
cell.userInput.text = bestString
}
}else if let error = error{
print(error)
}
}
})
}
Я получаю данные из локального файла JSON, и это модель:
struct RepeatTask: Codable {
let name: String
let label: String
let conditionWord: String
}
Возможно, кто-то мог бы помочь мне с этим?
1 ответ
Здесь недостаточно кода, чтобы воссоздать вашу проблему, в будущем приведите минимальный, полный и проверяемый пример. К сожалению, никто не может предложить вам эффективное решение, чтобы помочь вам решить проблему, если они не могут воссоздать проблему.
Однако я верю, что понимаю, чего вы пытаетесь достичь:
- Модельный объект, т.е.
struct
, - Протокол с реализацией по умолчанию, который одинаков для всех ячеек.
TableViewCell
класс, соответствующий протоколу, который вызывает методы протокола.- TableViewDelegate и источник данных для управления объектами из 1.
Учтите следующее:
import UIKit
/// 1.
/// Data model for "Repeat Cell Objects"
struct RepeaterModel {
var outputText:String?
var inputAudio:Data?
}
/// 2.
/// Allows a cell to delegate listening and repeating (speaking)
protocol RepeatableCell {
func listen()
func speak()
}
// Extend your protocol to add a default implementation,
// that way you can just confrom to the protocol
// without implementing it every time, in every cell class.
extension RepeatableCell {
func listen() {
print("default implementation for listen")
}
func speak(){
print("default implementation for speak")
}
}
/// 3.
final class RepeatCell: UITableViewCell, RepeatableCell {
// MARK: - Properties
var model:RepeaterModel? {
didSet {
DispatchQueue.main.async {
self.titleLabel.text = self.model?.outputText
}
}
}
// MARK: - Views
lazy var listenButton: UIButton = {
let btn = UIButton(type: .system)
btn.setTitle("Listen", for: .normal)
btn.addTarget(self, action: #selector(activateListen), for: .touchUpInside)
btn.setTitleColor(.white, for: .normal)
btn.backgroundColor = .blue
btn.translatesAutoresizingMaskIntoConstraints = false
return btn
}()
lazy var speakButton: UIButton = {
let btn = UIButton(type: .system)
btn.setTitle("Speak", for: .normal)
btn.addTarget(self, action: #selector(activateSpeak), for: .touchUpInside)
btn.setTitleColor(.white, for: .normal)
btn.backgroundColor = .green
btn.translatesAutoresizingMaskIntoConstraints = false
return btn
}()
let titleLabel: UILabel = {
let l = UILabel()
l.translatesAutoresizingMaskIntoConstraints = false
l.textColor = .black
l.textAlignment = .center
l.text = "No Text"
return l
}()
//MARK: - Initializers
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
self.setup()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
//MARK: - Class Methods
func setup() {
self.contentView.addSubview(listenButton)
self.contentView.addSubview(speakButton)
self.contentView.addSubview(titleLabel)
let spacing: CGFloat = 25.0
//Listen top left
listenButton.topAnchor.constraint(equalTo: self.contentView.topAnchor, constant: spacing).isActive = true
listenButton.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor, constant: spacing).isActive = true
listenButton.widthAnchor.constraint(equalToConstant: 100).isActive = true
listenButton.heightAnchor.constraint(equalToConstant: 50).isActive = true
// title label, center top.
titleLabel.topAnchor.constraint(equalTo: self.contentView.topAnchor, constant: spacing).isActive = true
titleLabel.leadingAnchor.constraint(equalTo: self.listenButton.trailingAnchor, constant: spacing).isActive = true
titleLabel.trailingAnchor.constraint(equalTo: self.speakButton.leadingAnchor, constant: -spacing).isActive = true
titleLabel.heightAnchor.constraint(equalToConstant: 50).isActive = true
//Speak top right
speakButton.topAnchor.constraint(equalTo: self.contentView.topAnchor, constant: spacing).isActive = true
speakButton.trailingAnchor.constraint(equalTo: self.contentView.trailingAnchor, constant: -spacing).isActive = true
speakButton.widthAnchor.constraint(equalToConstant: 100).isActive = true
speakButton.heightAnchor.constraint(equalToConstant: 50).isActive = true
}
@objc func activateListen() {
print("listen was pressed! on cell \(self.model?.outputText ?? "No Text")")
/// The user wants to listen
// call the delegate method..
listen()
// use self.model?.outputText
}
@objc func activateSpeak() {
print("Speak was pressed! on cell \(self.model?.outputText ?? "No Text")")
/// The user is speaking, record audio
// call the delegate method..
speak()
//self.model?.inputAudio = somedata
}
}
/// 4.
class ViewController: UITableViewController {
// Array of your model objects
var objects:[RepeaterModel] = []
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.register(RepeatCell.self, forCellReuseIdentifier: "Repeat")
// create or fetch model objects
let items = [
RepeaterModel(outputText: "1st Cell", inputAudio: nil),
RepeaterModel(outputText: "2nd Cell", inputAudio: nil),
RepeaterModel(outputText: "3rd Cell", inputAudio: nil),
RepeaterModel(outputText: "4th Cell", inputAudio: nil),
RepeaterModel(outputText: "5th Cell", inputAudio: nil),
RepeaterModel(outputText: "6th Cell", inputAudio: nil),
RepeaterModel(outputText: "8th Cell", inputAudio: nil),
RepeaterModel(outputText: "9th Cell", inputAudio: nil),
RepeaterModel(outputText: "10th Cell", inputAudio: nil),
RepeaterModel(outputText: "11th Cell", inputAudio: nil),
RepeaterModel(outputText: "12th Cell", inputAudio: nil)
]
self.objects += items
}
//MARK: - TableView Methods
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
// 25 top spacing + 50 view element width + 25 bottom spacing
return 100.0
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return objects.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = self.tableView.dequeueReusableCell(withIdentifier: "Repeat") as? RepeatCell {
cell.model = objects[indexPath.row]
// other cell stuff
return cell
}
return UITableViewCell()
}
}
Нажатие "Слушать", затем "Говорить" в каждой ячейке, идущей вниз, приводит к следующему выводу: