RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1094670
Accepted
Иван Маслов
Иван Маслов
Asked:2020-03-14 23:29:22 +0000 UTC2020-03-14 23:29:22 +0000 UTC 2020-03-14 23:29:22 +0000 UTC

无法开启定时器

  • 772

我想让它在按下按钮时打开计时器,计算秒数,停止后,再次播放时,它从按下暂停时停止的秒数开始计数。但是现在我没有随着时间的推移而发生变化,尽管按钮上的图像发生了变化。编码:

//MusicViewController

private var second64: Int64?

private var second = TimeInterval()

private var time: String?

//В этом методе мы считаем секунды
    @objc private func countSeconds( _ : TimeInterval) -> TimeInterval{

        if second > 0.0{

           second -= 1.0

            second64 = Int64(second)
            time = TimeFormatter().convertTimeToString(second64)

        }



        return second
    }



  func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

//Воспроизводим длительность аудиозаписи в основном потоке
           second64 = audio.duration
                    time = TimeFormatter().convertTimeToString(second64)



                    var timer = Timer()

                    if button.title(for: .normal) == "▶️"{
                        if button.isSelected{

                            DispatchQueue.main.asyncAfter(deadline: .now() + 1.0){

                                timer = self.setTimer()



                                cell.durationLabel.text = self.time

                            }

                        }

                        else if button.title(for: .selected) == "⏸" {

                            if button.isSelected{
                            DispatchQueue.main.asyncAfter(deadline: .now() + 1.0){
                                timer.invalidate()

                                cell.durationLabel.text = self.time
                            }
                            }
                    }
                    }
                }

                    else{
                    cell.singerLabel.text! = ""
                    cell.titleLabel.text! = ""
                }
}
//Метод в протоколе для взаимодействия с презентером.
func setTimer () -> Timer{

      let timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(countSeconds(_:)), userInfo: nil, repeats: true)
    print(second)
      return timer
  }
}


class TimeFormatter{

private var seconds = TimeInterval()
//Метод, преобразующий время в нужный формат
private func timeFormatter (_ : TimeInterval) -> DateComponentsFormatter{
    let formatter = DateComponentsFormatter()
    // Длительность будет отображаться как 1:00:00
    if seconds > 59.59{
        formatter.allowedUnits = [.hour, .minute, .second]
    }

    else{
        formatter.allowedUnits = [.minute, .second]
    }

    formatter.unitsStyle = .positional
    formatter.zeroFormattingBehavior = .pad


    return formatter
}

//Метод, передающий информацию о длительности записи в приложение
func convertTimeToString(_ number: Int64?) -> String?{



    if let unwrappedNumber = number{

        seconds = TimeInterval(integerLiteral: unwrappedNumber)

        print(seconds)
    }

    let formatter = timeFormatter(seconds)
    let timeString = formatter.string(from: seconds)

    return timeString


}

}

UPD。现在我的代码如下所示: //MusicViewController

私有变量索引 = Int()

private var posts: [Post] = []

private var timer: Timer?

private var playingCell: MusicTableViewCell?{

    let count = store!.getPostsCount()

    for i in 0...count-1{

        index = i

        let post = store!.getPost(for: index)

        posts.append(post)
    }

    let indexPath = IndexPath(row: index, section: 0)

    return tableView.cellForRow(at: indexPath) as? MusicTableViewCell

私有函数重置(){

    guard let cell = playingCell, let button = cell.playButton, let post = store?.getPost(for: index), let attachments = post.attachments, let audio = attachments[index].audio else {return}

    button.isSelected = false

    second64 = audio.duration

    cell.second = cell.makeTimeIntervalFromInt(second64)

}

//方法在当前时刻停止音乐 private func pauseMusic() {

    guard let cell = playingCell, let playbutton = cell.playButton else {return}

    playbutton.isSelected = false

    timer?.invalidate()

}

私有变量 second64: Int64? //private let second = TimeInterval(integerLiteral: second64!)

扩展 MusicViewController: UITableViewDataSource, MusicTableViewCellDelegate{

func musicShouldStartPlaying(_ cell: MusicTableViewCell) {

    if cell !== playingCell{

        musicShouldStopPlaying(cell)

    }

    cell.playButton.isSelected = true

    timer = cell.setTimer()

}

func musicShouldStopPlaying(_ cell: MusicTableViewCell) {

    if cell.second == 0.0 || cell !== playingCell{

        cell.playButton.isSelected = false

        pauseMusic()

        reset()

    }

    else{
        cell.playButton.isSelected = false

        pauseMusic()

    }

    cell.playButton.isSelected = false

    pauseMusic()

}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let button = cell.playButton!

    button.actions(forTarget: button, forControlEvent: .touchUpInside)
    cell.delegate = self
    cell.index = indexPath.row
    cell.second = cell.makeTimeIntervalFromInt(second64)
}
//MusicTableViewCell
 var second64: Int64?
var index: Int!

var second = TimeInterval()

private var time: String?

weak var delegate: MusicTableViewCellDelegate?
func makeTimeIntervalFromInt( _ : Int64?) -> TimeInterval{
    if let currentSecond = second64{
    second = TimeInterval(integerLiteral: currentSecond)
    }
    return second
}

//View 与 Presenter 协议 ViewProto 交互的协议:class {

//Метод, вызывающий презентер во View
func setPresenter(_ presenter: PresenterProto)

//Метод, обновляющий посты
func updateData()

// 函数重置()

}

// Presenter 交互协议与 View 协议 PresenterProto: class {

// Метод, вызывающий View в презентере
func viewLoaded(with view: ViewProto)

//Метод, позволяющий узнать количество постов в массиве
func getPostsCount() -> Int

//Показывает содержание конкретного поста
func getPost(for index: Int) -> Post

}

协议 MusicTableViewCellDelegate: class{ func musicShouldStartPlaying(_ cell: MusicTableViewCell)

func musicShouldStopPlaying(_ cell: MusicTableViewCell)

//func reset(_ cell: MusicTableViewCell)

}

'''

在此处输入图像描述

swift
  • 1 1 个回答
  • 10 Views

1 个回答

  • Voted
  1. Best Answer
    schmidt9
    2020-03-25T00:39:13Z2020-03-25T00:39:13Z

    这是使用可更新计时器的示例。

    添加

    您需要在countSeconds下面的方法中更新时间

    class ViewController: UIViewController {
    
        @IBOutlet var playButton: UIButton!
        @IBOutlet var durationLabel: UILabel!
    
        private var seconds = TimeInterval()
    
        private var timeString = ""
    
        private var timer: Timer?
    
        private var isPlaying = false
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            playButton.setTitle("Play", for: .normal)
            seconds = 100
        }
    
        @IBAction func playButtonTouchUpInside(_ sender: UIButton) {
            togglePlayback()
    
            playButton.setTitle(isPlaying ? "Stop" : "Play", for: .normal)
        }
    
        @objc private func countSeconds(_ sender: Timer) {
            if seconds > 0.0 {
                seconds -= 1.0
                timeString = TimeFormatter.convertTimeToString(seconds)
    
                DispatchQueue.main.async {
                    self.durationLabel.text = self.timeString
                }
            }
        }
    
        func togglePlayback() {
            isPlaying = !isPlaying
    
            if isPlaying {
                startTimer()
            } else {
                stopTimer()
            }
        }
    
        func startTimer() {
            timer = Timer.scheduledTimer(
                timeInterval: 1.0,
                target: self,
                selector: #selector(countSeconds(_ :)),
                userInfo: nil,
                repeats: true)
        }
    
        func stopTimer() {
            timer?.invalidate()
        }
    
    }
    

    补充 2

    这个任务对我来说似乎很有趣,我完全重写了问题作者的实现,并做了一个测试项目,其中包含切换列表中的条目的逻辑(github)

    Первоначально я перенес логику переключения и отслеживания времени в ячейки, однако это оказалось неверным решением из-за повторного использования ячеек при прокрутке и соответственно остановки таймера, работающего в выбранной ячейке, поэтому я сделал общий таймер во вью контроллере, и здесь столкнулся с тем, что обычный Timer тоже останавливается при прокрутке, так как запускается в основном цикле событий (main loop).

    Поэтому я использовал реализацию фонового таймера отсюда

    Замечания:

    • иногда при возобновлении таймера в начале быстро проскакивает первая секунда
    • неоптимальный вариант получения текущей ячейки для обновления времени в ней при большом списке

    Класс ячейки содержит кнопку переключения и лейбл для вывода времени, внутри управляет переключением кнопки и делегирует события переключения во вью контроллер

    class RecordDurationFormatter : DateComponentsFormatter {
    
        override init() {
            super.init()
            setup()
        }
    
        required init?(coder: NSCoder) {
            super.init(coder: coder)
            setup()
        }
    
        private func setup() {
            unitsStyle = .positional
            zeroFormattingBehavior = .pad
        }
    
        /// Метод, преобразующий время в нужный формат
        func format(_ seconds: TimeInterval) -> String? {
    
            // Длительность будет отображаться как 1:00:00
            if seconds > 59.59 {
                allowedUnits = [.hour, .minute, .second]
            } else {
                allowedUnits = [.minute, .second]
            }
    
            return string(from: seconds)
        }
    }
    
    
    protocol RecordTableViewCellDelegate : class {
    
        func recordTableViewCellShouldStartPlaying(_ cell: RecordTableViewCell)
        func recordTableViewCellShouldPausePlaying(_ cell: RecordTableViewCell)
    
    }
    
    class RecordTableViewCell: UITableViewCell {
    
        @IBOutlet var playButton: UIButton!
        @IBOutlet var timeLabel: UILabel!
    
        private let stoppedTitle = "▶️"
        private let playingTitle = "⏸"
    
        let formatter = RecordDurationFormatter()
    
        private var timer: Timer?
    
        var recordIndex: Int!
    
        var isPlaying: Bool = false {
            didSet {
                togglePlayButtonTitle(playing: isPlaying)
            }
        }
    
        var seconds: TimeInterval = 0 {
            didSet {
                updateTimeLabelText()
            }
        }
    
        weak var delegate: RecordTableViewCellDelegate?
    
    
        override func awakeFromNib() {
            super.awakeFromNib()
            setup()
        }
    
        private func setup() {
            togglePlayButtonTitle(playing: false)
        }
    
        // MARK: UI Update
    
        private func togglePlayButtonTitle(playing: Bool) {
            playButton.setTitle(playing ? playingTitle : stoppedTitle, for: .normal)
        }
    
        func updateTimeLabelText() {
            DispatchQueue.main.async {
                self.timeLabel.text = self.formatter.format(self.seconds)
            }
        }
    
        // MARK: UI Events
    
        @IBAction func playButtonTouchUpInside(_ sender: UIButton) {
            isPlaying = !isPlaying
    
            if isPlaying {
                delegate?.recordTableViewCellShouldStartPlaying(self)
            } else {
                delegate?.recordTableViewCellShouldPausePlaying(self)
            }
        }
    
    }
    

    视图控制器包含一个表,控制定时器和记录之间的切换

    class Record {
    
        var isPlaying = false
        var duration: TimeInterval = 100
        lazy var currentSeconds = duration
    
        func reset() {
            isPlaying = false
            currentSeconds = duration
        }
    
        func countDown() -> TimeInterval {
            if currentSeconds > 0 {
                currentSeconds -= 1.0
            }
    
            return currentSeconds
        }
    
    }
    
    class RecordsViewController: UIViewController {
    
        @IBOutlet var tableView: UITableView!
    
        private var seconds = TimeInterval()
    
        /// Using background timer because common Timer is getting suspended
        /// on table view scroll (because of schedule on main loop)
        private var timer = RepeatingTimer(timeInterval: 1)
    
        private var records: [Record] = []
    
        private var playingRecord: Record?
    
        // TODO: maybe optimize because is gets called by timer via playingCell every second
        private var playingRecordIndex: Int? {
            records.firstIndex { $0 === playingRecord }
        }
    
        private var playingCell: RecordTableViewCell? {
            guard let index = playingRecordIndex else {
                return nil
            }
    
            let indexPath = IndexPath(row: index, section: 0)
            return tableView.cellForRow(at: indexPath) as? RecordTableViewCell
        }
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            let nibName = String(NSStringFromClass(RecordTableViewCell.self).split(separator: ".").last!)
            self.tableView.register(UINib(nibName: nibName, bundle: nil), forCellReuseIdentifier: "cell")
    
            for _ in 0..<100 {
                records.append(Record())
            }
        }
    
        // MARK: Playback
    
        /// Resume or start record
        func startRecord(with index: Int) {
            let record = records[index]
            record.isPlaying = true
            playingRecord = record
    
            startTimer()
        }
    
        func stopPlayingNowRecord() {
            guard let record = playingRecord, let cell = playingCell else {
                return
            }
    
            record.reset()
    
            cell.seconds = record.duration
            cell.isPlaying = false
    
            stopTimer()
        }
    
        func pausePlayingNowRecord() {
            guard let record = playingRecord else {
                return
            }
    
            record.isPlaying = false
    
            stopTimer()
        }
    
        // MARK: Timer
    
        @objc private func countSeconds() {
            guard let record = self.playingRecord else {
                return
            }
    
            seconds = record.countDown()
    
            DispatchQueue.main.async {
                guard let cell = self.playingCell else {
                    return
                }
    
                cell.seconds = self.seconds
            }
        }
    
        private func startTimer() {
    
            if timer.eventHandler == nil {
                timer.eventHandler = {
                    self.countSeconds()
                }
            }
    
            timer.resume()
        }
    
        private func stopTimer() {
            timer.suspend()
        }
    
    }
    
    extension RecordsViewController : UITableViewDataSource {
    
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            records.count
        }
    
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! RecordTableViewCell
            cell.delegate = self
            cell.recordIndex = indexPath.row
    
            let record = records[indexPath.row]
            cell.seconds = record.currentSeconds
            cell.isPlaying = record.isPlaying
    
            return cell
        }
    
    }
    
    extension RecordsViewController : RecordTableViewCellDelegate {
    
        func recordTableViewCellShouldStartPlaying(_ cell: RecordTableViewCell) {
            if cell !== playingCell {
                // stop previous record if any
                stopPlayingNowRecord()
            }
    
            startRecord(with: cell.recordIndex)
        }
    
        func recordTableViewCellShouldPausePlaying(_ cell: RecordTableViewCell) {
            pausePlayingNowRecord()
        }
    
    }
    
    • 1

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    如何从列表中打印最大元素(str 类型)的长度?

    • 2 个回答
  • Marko Smith

    如何在 PyQT5 中清除 QFrame 的内容

    • 1 个回答
  • Marko Smith

    如何将具有特定字符的字符串拆分为两个不同的列表?

    • 2 个回答
  • Marko Smith

    导航栏活动元素

    • 1 个回答
  • Marko Smith

    是否可以将文本放入数组中?[关闭]

    • 1 个回答
  • Marko Smith

    如何一次用多个分隔符拆分字符串?

    • 1 个回答
  • Marko Smith

    如何通过 ClassPath 创建 InputStream?

    • 2 个回答
  • Marko Smith

    在一个查询中连接多个表

    • 1 个回答
  • Marko Smith

    对列表列表中的所有值求和

    • 3 个回答
  • Marko Smith

    如何对齐 string.Format 中的列?

    • 1 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5