在Swift协议中,IBActions的更好策略是什么?

Ang*_*qui 7 protocols ibaction ios swift swift-protocols

我正在创建一个Swift项目,我想定义一个特定的协议来强制其他组件来实现一个animate方法:

protocol AnimatableBehavior {
    @IBAction func animate()
}
Run Code Online (Sandbox Code Playgroud)

问题是我希望这个方法是一个IBAction,但我从XCode得到这个错误:

只有实例方法可以声明'IBAction'

我的问题是,你将如何实现这样的事情?

我考虑过:

  1. 删除@IBAction,但后来我需要记住在每个实现的类中添加它.不是很优雅,容易出错.
  2. 创建一个基类而不是协议,但后来我强制所有组件继承我的基类而不是他们自己选择的基类,所以它不是一个有效的选项.

还有其他想法吗?


编辑:回复以下评论.

IBAction关于协议的想法是因为在项目中将有许多不同的开发人员实现小的UI组件,所有这些组件都具有animate方法.这些组件可以通过编程方式添加,也可以通过Interface Builder添加,它们总是非常方便,IBAction因为我打算从IB文件中组合它们以最大限度地简化视图控制器(这显然是一个仅查看任务).

因此,下面提出的在控制器中添加一个只调用animate组件的方法的解决方案并不好,因为它是冗余代码并使Controller更依赖于View.

让开发人员记住IBAction在方法上添加关键字的想法是可行的,但正如我所说它容易出错(并且我的意思是会有一些遗忘),我想确保这是总是可以从IB访问.它还增加了额外的认知负荷,因为我需要记录IBAction协议的缺失并请求实现者手动添加它.

我知道这不是在iOS中工作的常见方式UIKit,但这就是我发布问题的原因,也许有人有另一种想法.

nhg*_*rif 10

拥有一个协议是没有任何意义的@IBAction. @IBAction当您从Interface Builder控制+拖动到实际的源代码时,它只不过是Interface Builder的关键字.

这只是一个简单的误解,@IBAction实际上是什么和做了什么.

  1. 不必将方法标记@IBAction为使其成为UI元素操作的目标.您可以使用addTargetUI元素具有的一组方法以编程方式将任何方法连接到任何操作.该方法不必标记为@IBAction执行此操作.

  2. 无论协议是否将方法定义为@IBAction,符合协议的类都可以添加它(并且仍然符合协议.

    protocol FooProtocol {
        func doSomething()
    }
    
    class ViewControllerA: UIViewController, FooProtocol {
        @IBAction func doSomething() {
            // do something
        }
    } 
    
    class ViewControllerB: UIViewController, FooProtocol {
        func doSomething() {
            // do something
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

    这两种视图控制器子类符合协议,并具有@IBActionONLY,如果你打算挂钩的必要行动,从界面生成器!


最终,无论你想做什么,如果你认为@IBAction你的协议中有必要,我认为你采取了错误的方法.如果不了解关于你实际做什么的更多细节,很难说正确的方法是什么,但是@IBAction属于协议是没有意义的.

对我来说,似乎你的协议强制执行的方法根本不应该与@IBAction方法联系在一起.相反,无论用户交互应该触发动画,都应该依次调用该animate方法.例如,如果我们不讨论协议,我的建议就是这种设置:

class ViewController: UIViewController {
    @IBAction func buttonThatStartsAnimation {
        self.animate()
    }

    func animate {
        // code that does all the animation
    }
}
Run Code Online (Sandbox Code Playgroud)

因此,使用协议,我们应该在实际启动动画代码的方法之间采取相同的职责分离(在协议的情况下,这显然是其他一些外部类),并且该animate方法应该只处理相关的操作动画.

重要的是,作为一般规则,您不应直接从定义它们的类外部直接引用您的@IBAction方法或@IBOutlet变量.

  • 谢谢你花时间回答.但是,我必须不同意你的一些意见.我完全清楚"IBAction"意味着什么,但这并没有改变这个问题.检查我的编辑. (5认同)
  • 尽管如此,我完全不同意.在协议中声明一些功能集非常有意义.例如,在您的应用程序中,一半的`ViewControllers`可能具有在多个不同位置呈现用户配置文件控制器的功能,并且在协议中放置`@IBAction func actionPresentProfile(sender:)`可能非常有用. (4认同)