【问题标题】:Only instance methods can be declared @IBAction只能声明实例方法@IBAction
【发布时间】:2018-01-17 19:41:42
【问题描述】:

我是 Xcode 的新手,而且一般都在编码,所以请耐心等待,哈哈。我正在为一个科学展览项目开发我的第一个应用程序,该项目基于选项卡,有两个主要页面。一页包含多个开关;无论打开哪个开关,都决定了另一页上的大按钮播放什么声音或动画。

在查看了几个教程并创建了我的故事板之后,我开始编写将动作连接到按钮和开关的部分。我在有pushButton 函数的行上继续收到以下错误:Only instance methods can be declared @IBAction

我检查了括号和方括号,我认为没有错误,但由于我是初学者,我可能会遗漏一些东西。我的代码粘贴在下面,不胜感激。一旦我弄清楚了这个问题,空的开关功能就会像第一个一样。 :)

import UIKit
import AVFoundation
import AVKit

class FirstViewController: UIViewController {
    var audioPlayer = AVAudioPlayer()
    var CatSound = URL(fileURLWithPath: Bundle.main.path(forResource:    "CatSound", ofType: "mp3")!)

    //Mark: Properties
    @IBOutlet var pushButton: UIButton!

    @IBAction func meowSwitch(_ sender: UISwitch) {
        while (sender.isOn == true) {
            @IBAction func pushButton(_ sender: UIButton) {
                let CatSound = URL(fileURLWithPath: Bundle.main.path(forResource:  "CatSound", ofType: "mp3")!)
                do {
                    audioPlayer = try AVAudioPlayer(contentsOf: CatSound)
                    audioPlayer.prepareToPlay()
                } catch {
                    print("Problem in getting File")
                }
                audioPlayer.play()
            }
        }

    }

    @IBAction func barkSwitch(_ sender: UISwitch) {
    }

    @IBAction func carSwitch(_ sender: UISwitch) {
    }

    @IBAction func trainSwitch(_ sender: UISwitch) {
    }

    @IBAction func helloSwitch(_ sender: UISwitch) {
    }

    @IBAction func applauseSwitch(_ sender: UISwitch) {
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

【问题讨论】:

    标签: ios swift xcode


    【解决方案1】:

    问题在于:

    @IBAction func meowSwitch(_ sender: UISwitch) {
        while (sender.isOn == true) {
            @IBAction func pushButton(_ sender: UIButton) {
                .....
            }
        }
    }
    

    你不能像这样在另一个函数中声明一个函数。

    您应该创建一个单独的函数func playMeowSound(){...},其中包含pushButton(_ sender: UIButton) 中的代码,然后执行:

    @IBAction func meowSwitch(_ sender: UISwitch) {
        while (sender.isOn == true) {
            playMeowSound()
        }
    }
    

    【讨论】:

      【解决方案2】:

      这两个函数不能在彼此内部

       @IBAction func meowSwitch(_ sender: UISwitch) {
      while (sender.isOn == true) {
          @IBAction func pushButton(_ sender: UIButton) {
              let CatSound = URL(fileURLWithPath: Bundle.main.path(forResource:  "CatSound", ofType: "mp3")!)
              do {
                  audioPlayer = try AVAudioPlayer(contentsOf: CatSound)
                  audioPlayer.prepareToPlay()
              } catch {
                  print("Problem in getting File")
              }
              audioPlayer.play()
          }
      }
      
      }
      

      这样分割

        @IBAction func pushButton(_ sender: UIButton) {
          let CatSound = URL(fileURLWithPath: Bundle.main.path(forResource:  "CatSound", ofType: "mp3")!)
          do {
              audioPlayer = try AVAudioPlayer(contentsOf: CatSound)
              /// set repeats here if you want
              audioPlayer.numberOfLoops = -1
              audioPlayer.prepareToPlay()
          } catch {
              print("Problem in getting File")
          }
          audioPlayer.play()
      

      ////

       @IBAction func meowSwitch(_ sender: UISwitch) {
      
             if(sender.isOn) {      
                self.pushButton(self.pushBtn)    
             }
      
        }
      

      【讨论】:

        【解决方案3】:

        当你将一个函数放入另一个函数时,内部函数属于外部函数,而不是类的实例。

        你的代码设置方式pushButton属于meowSwitch方法而不是FirstViewController类,因此你不能使用@IBAction关键字。

        根据您描述项目的方式,您应该使用不同的界面来查看。假设您希望用户在按下按钮时选择要播放的“声音或动画”,UIPickerView 可能对您更有效。

        使用开关意味着用户可以一次将它们全部打开,那么当用户按下按钮时会发生什么?

        鉴于您想将内容拆分为两个视图控制器,每个视图控制器都在它们自己的选项卡中,我会让第一个选项卡负责选择器,第二个选项卡有触发所选项目的按钮。

        在第一个视图控制器中,您将使用func pickerView(_ : ,didSelectRow: , inComponent: ) 将用户的选择存储在用户默认值中。

        func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
            if let chosen = self.pickerView(pickerView, titleForRow: row, forComponent: component) {
                UserDefaults.standard.set(chosen, forKey: "selected")
            }
        }
        

        请注意,要使 UIPickerView 正常工作,还需要进行更多设置,但有很多教程可以解释它。

        然后第二个视图控制器会在按下按钮时读取默认值,并做出相应的响应。

        如果所有选项都是音频文件,并且它们的名称与您在选择器视图中显示的名称相匹配,您可以使用存储在用户默认值中的字符串来播放正确的音频。

        @IBAction func pushButton(_ sender: UIButton) {
            guard let selected = UserDefaults.standard.string(forKey: "selected") else { return }
            let sound = URL(fileURLWithPath: Bundle.main.path(forResource:  selected, ofType: "mp3")!)
            do {
                audioPlayer = try AVAudioPlayer(contentsOf: sound)
                audioPlayer.prepareToPlay()
            } catch {
                print("Problem in getting File")
            }
            audioPlayer.play()
        }
        

        【讨论】:

          【解决方案4】:

          我希望这是你想要的:

          import UIKit
          import AVFoundation
          import AVKit
          
          class FirstViewController: UIViewController {
              var audioPlayer = AVAudioPlayer()
              var CatSound = URL(fileURLWithPath: Bundle.main.path(forResource:    "CatSound", ofType: "mp3")!)
          
              //Mark: Properties
          
              @IBAction func pushButton(_ sender: UIButton) {
                  if UserDefaults.standard.playMeowSound {
                      playMeow()
                  } // else if UserDefaults.standard.playBarkSound { etc.
              }
          
              func playMeow() {
                  let CatSound = URL(fileURLWithPath: Bundle.main.path(forResource:  "CatSound", ofType: "mp3")!)
                  do {
                      audioPlayer = try AVAudioPlayer(contentsOf: CatSound)
                      audioPlayer.prepareToPlay()
                  } catch {
                      print("Problem in getting File")
                  }
                  audioPlayer.play()
              }
          }
          
          class SecondViewController: UIViewController {
          
          
              @IBAction func meowSwitch(_ sender: UISwitch) {
                  UserDefaults.standard.playMeowSound = sender.isOn
                  if sender.isOn == true {
                      // turn off all the other switches, e.g.:
                      // barkSwitch.isOn = false
                      // UserDefaults.standard.playBarkSound = false
                  }
              }
          }
          
          extension UserDefaults {
              private static let playMeowSoundKey = "org.stackoverflow.playMeowSoundKey"
          
              var playMeowSound: Bool {
                  get {
                      return UserDefaults.standard.bool(forKey: UserDefaults.playMeowSoundKey)
                  }
                  set {
                      UserDefaults.standard.set(newValue, forKey: UserDefaults.playMeowSoundKey)
                  }
              }
          }
          

          pushButton 是一个链接到按钮的@IBAction。按下时,此处理程序会测试哪个开关已打开,并播放您需要的声音。您需要@IBOutlets 作为开关,这样您就可以测试它们的状态以确定哪个开关处于打开状态。

          【讨论】:

          • 代码不再显示这部分的错误,但我不确定如何将开关连接到我的界面生成器中的那些,因为它们位于第二个视图控制器中。有没有办法做到这一点?有必要建立这种联系吗?
          • @AbbyCornell 好吧,您需要对这些开关有一些访问权限才能确定要播放哪种声音。但是如果开关与播放声音的按钮位于不同的 viewController 中,那就有点麻烦了艰难的。您必须在它们各自的控制器中为开关创建@IBOutlets,并在那里放置它们之间的切换逻辑。然后,当用户转到该控制器时,您必须以某种方式将该信息传递给带有按钮的控制器。由于我无法访问您的其余代码,因此很难提出建议。
          • @AbbyCornell 但一种绝对可行的方法是将开关的当前状态存储在 UserDefaults 中(基本上将其存储到永久存储中),每次开关更改时,然后按下按钮即可阅读从那里的当前状态..这样你就可以使用 UserDefaults 在这些控制器之间“传递”该信息
          • @AbbyCornell 我已经更新了我的答案,为您提供一个起点
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-09-20
          • 1970-01-01
          • 2019-07-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多