提问人:Lio 提问时间:3/9/2021 最后编辑:Lio 更新时间:3/9/2021 访问量:175
Swift 和 @objc 方法:如何转换方法,使其可以用@objc表示?
Swift and @objc methods: How do I transform a method so that it can be represented by @objc?
问:
由于 Swift 是我的第一门编程语言,而且我没有 Objective C 经验...... 我很难理解与方法相关的@objc。
如何使用@objc语法来符合我的方法? 有没有另一种方法可以在不使用 #selector 语法的情况下选择方法?
这是我遇到困难的代码(主要是 startGame 方法的@objc尝试):
import UIKit
@objc class ViewController: UITableViewController {
var allWords = [String]()
var usedWords = [String]()
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.rightBarButtonItem =
UIBarButtonItem(barButtonSystemItem: .add, target: self, action:
#selector(promptForAnswer))
navigationItem.leftBarButtonItem = UIBarButtonItem(title: "New
Word", style: .plain, target: self, action: #selector(startGame))
if let startWordsURL = Bundle.main.url(forResource: "start",
withExtension: "txt") {
if let startWords = try? String(contentsOf: startWordsURL) {
allWords = startWords.components(separatedBy: "\n")
}
}
if allWords.isEmpty {
allWords = ["silkworm"]
}
@objc func startGame() {
title = allWords.randomElement()
usedWords.removeAll(keepingCapacity: true)
tableView.reloadData()
{
startGame()
}
答:
我认为您在@objc方法中有语法错误。它应该是:
@objc
func functionName() {
}
对你来说,这将是:
@objc
func startGame() {
title = allWords.randomElement()
usedWords.removeAll(keepingCapacity: true)
tableView.reloadData()
}
几点观察:
您不需要在视图控制器声明中声明。
@objc
两个操作/选择器方法应带有限定符。
@objc
我建议你给这两个方法一个描述性的名称,清楚地表明它们在用户点击特定按钮时被调用,例如:
@objc func didTapNewWord(_ sender: UIBarButtonItem) { ... } @objc func didTapAdd(_ sender: UIBarButtonItem) { ... }
请注意,我还为这些方法添加了一个参数。这使得它们是按钮处理程序是完全明确的。您不需要这样做,但现在您可以浏览代码并立即了解该方法的用途。
显然,您将相应地更改添加这些目标操作的代码:
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(didTapAdd(_:))) navigationItem.leftBarButtonItem = UIBarButtonItem(title: "New Word", style: .plain, target: self, action: #selector(didTapNewWord(_:)))
小心牙套的放置。Swift 允许您在函数中声明函数。因此,请确保这些选择器方法是视图控制器的实例方法,而不是在另一个函数(即 )。
viewDidLoad
如果您开始忘记大括号,您可以选择此文件中的所有代码并按 +(或在 Xcode 菜单中,“编辑器”»“结构”»“重新缩进”)。如果你在某处缺少大括号,代码的重新缩进会让你跳出来。controli
所以把它们放在一起,你会得到类似的东西:
// ViewController.swift
import UIKit
class ViewController: UITableViewController {
var allWords = [String]()
var usedWords = [String]()
override func viewDidLoad() {
super.viewDidLoad()
configureButtons()
fetchData()
}
}
// MARK: - Actions
extension ViewController {
@objc func didTapNewWord(_ sender: UIBarButtonItem) {
startGame()
}
@objc func didTapAdd(_ sender: UIBarButtonItem) {
...
}
}
// MARK: - UITableViewDataSource
extension ViewController {
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
...
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
...
}
}
// MARK: - Private utility methods
private extension ViewController {
func configureButtons() {
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .add,
target: self,
action: #selector(didTapAdd(_:)))
navigationItem.leftBarButtonItem = UIBarButtonItem(title: "New Word",
style: .plain,
target: self,
action: #selector(didTapNewWord(_:)))
}
func fetchData() {
guard
let startWordsURL = Bundle.main.url(forResource: "start", withExtension: "txt"),
let startWords = try? String(contentsOf: startWordsURL).components(separatedBy: "\n"),
!startWords.isEmpty
else {
allWords = ["silkworm"]
return
}
allWords = startWords.filter { !$0.isEmpty }
}
func startGame() {
title = allWords.randomElement()
usedWords.removeAll(keepingCapacity: true)
tableView.reloadData()
}
}
关于我的代码示例的一些最后观察(与您的问题没有直接关系,但只是为了解释为什么像我一样构建它):
我喜欢将方法放入扩展中,以便它们在逻辑组中。这样可以更轻松地一目了然地了解正在发生的事情。您还可以折叠/展开这些扩展,以便在编辑时可以专注于相关代码。
这些注释只是在 Xcode 跳转栏中放置了漂亮的部分标题,再次使在代码中跳转变得更加容易。
MARK
我个人不会在操作方法中放置任何东西,除了使用“业务逻辑”调用某个方法。这将“视图”代码(按钮的处理)与业务逻辑分开。总有一天,您可能会开始使用视图模型或演示者对象,因此现在接受这种职责分离将使最终的转换更容易。当你开始编写单元测试时,它也会使编写单元测试变得更容易(例如,你为“开始游戏”逻辑编写单元测试,而不是点击按钮)。
评论
startGame
func startGame()
viewDidLoad
viewDidLoad
["silkworm"]
@objc
}}
}