[译]iOS开发者在Swift中应避免过度使用@objc

栏目: Objective-C · 发布时间: 5年前

内容简介:就在前几天,我终于把项目迁移到了Swift2.2,在使用为了达到本文的目的,我简化了工作中项目的代码,但所有核心的思想都保留着。一种我经常在swift里用的模式是:为了重用的配置写protocols(协议)和extensions(扩展),特别是有Uikit的时候假设我们有一组视图控制器,每个控制器都需要一个 view model 和 一个“取消”按钮。每一个控制器需要各自响应 “cancel”按钮的点击事件。我们可以这样写:

就在前几天,我终于把项目迁移到了Swift2.2,在使用 SE-0022 建议的 #selector 语句时,我遇到了一些问题。如果在protocol extension中使用 #selector ,这个protocol必须添加 @Objc 修饰符。而之前的 Selector("method:") 语句则不需要添加。

通过协议的扩展配置视图控制器

为了达到本文的目的,我简化了工作中项目的代码,但所有核心的思想都保留着。一种我经常在swift里用的模式是:为了重用的配置写protocols(协议)和extensions(扩展),特别是有Uikit的时候

假设我们有一组视图控制器,每个控制器都需要一个 view model 和 一个“取消”按钮。每一个控制器需要各自响应 “cancel”按钮的点击事件。我们可以这样写:

struct ViewModel {
    let title: String
}

protocol ViewControllerType: class {
    var viewModel: ViewModel { get set }

    func didTapCancelButton(sender: UIBarButtonItem)
}
复制代码

如果就写成这样,那每个控制器都需要自己去添加和写一个一样的取消按钮。这样就会有很多一样的代码。我们可以通过扩展(用老的 Selector("") 语句)来解决:

extension ViewControllerType where Self: UIViewController {
    func configureNavigationItem() {
        navigationItem.leftBarButtonItem = UIBarButtonItem(
            barButtonSystemItem: .Cancel,
            target: self,
            action: Selector("didTapCancelButton:"))
    }
}
复制代码

现在每个符合协议的控制器都可以通过在 viewDidLoad() 里调用协议的 configureNavigationItem() 方法来配置取消按钮,是不是好多了~我们的控制器看起来是这样的:

class MyViewController: UIViewController, ViewControllerType {
    var viewModel = ViewModel(title: "Title")

    override func viewDidLoad() {
        super.viewDidLoad()
        configureNavigationItem()
    }

    func didTapCancelButton(sender: UIBarButtonItem) {
        // handle tap
    }
}
复制代码

这仅是一个简单的例子,但我们可以想象通过这个方式制造更多复杂的配置。

把以上代码段升级到 Swift 2.2后,是这样的:

extension ViewControllerType where Self: UIViewController {
    func configureNavigationItem() {
        navigationItem.leftBarButtonItem = UIBarButtonItem(
            barButtonSystemItem: .Cancel,
            target: self,
            action: #selector(didTapCancelButton(_:)))
    }
}
复制代码

但现在我们有了个问题,一个新的编译错误

Argument of '#selector' refers to a method that is not exposed to Objective-C.

Fix-it   Add '@objc' to expose this method to Objective-C
复制代码

@objc 试图破坏所有的东西

因为一系列的原因, 在原始的 ViewControllerType 协议中,我们并不能简单的给这个方法添加一个 @objc 修饰符。如果我们这么做了,那么所有的protocol都需要用 @objc 来标记,这将意味着:

@objc
@objc
ViewModel

到目前, @objc 在这里的唯一功能就是定义了一个普通的target-action selectors。尽管我们可以使用swift的强大功能,但是因为Cocoa依然贯穿我们的代码 Cocoa all the way down ,我们并没有正真的在写纯粹的swift - 除非我们开始在各个地方引入@objc。

我们在这的例子很简单,但是想象一下更复杂的类依赖关系图,大量使用Swift的值类型和当这个协议处在多个协议的中间层时。把引入 @objc 作为解决方案真是app的末日。如果我们这样做, @objc 这种做法会让我们的Swift代码毫无美感并变得乱糟糟。这会毁了所有的东西。

但是希望还是有的。

不使用 @objc 来避免乱糟糟

我们大可不必让为了让我们的Swifit代码能使用Objcetive-C的语法而使用 @objc

我们可以把protocol分解成多个protocol来去除 @objc ,然后我们再重组这些protocol。事实上,我们可以让编译器顺利编译和避免更改任何视图控制器的代码。

第一步,我们把protocol拆成2个。 ViewModelConfigurableNavigationItemConfigurable 。把 ViewControllerType 里的extension放到 NavigationItemConfigurable

protocol ViewModelConfigurable {
    var viewModel: ViewModel { get set }
}

@objc protocol NavigationItemConfigurable: class {
    func didTapCancelButton(sender: UIBarButtonItem)
}
复制代码

最终,我们可以把原 ViewControllerType protocol定义成 typealias

typealias ViewControllerType = protocol<ViewModelConfigurable, NavigationItemConfigurable>
复制代码

和迁移到Swift2.2之前比一切都很正常,而且我们定义的原视图控制器也没有发生任何改变,没有东西被破坏。如果你曾经遇到类似的情况,或者你也想阻止 @objc 带来的破坏(你应该这么做),我强烈建议采用这个策略。

这并不是显而易见的

现在的代码,我还是觉得有点不爽,当然,针对这个问题,这就是最Swift化的答案。当Xcode突然开始提示你并且很快的应用它的修复方案依然会把所有都破坏掉。特别是当Xcode提供的修复方案正中你下怀的时候,这个时候,上面说的到的这类解决方案并不能立即很清楚。

最后,在做了以上那些更改之后,我意识到总的来说这其实是一个很好的解决方案。。没有什么理由在一个地方只用一个协议。像 ViewModelConfigurableNavigationItemConfigurable 这两个协议分工明确。把不同的协议组合在一起始终都是最优雅、最适当的设计。


以上所述就是小编给大家介绍的《[译]iOS开发者在Swift中应避免过度使用@objc》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

超级运营术

超级运营术

韩叙 / 中信出版社 / 2017-5

新产品上线,为什么仅仅500次转发能带来300个内测用户? 为什么每一次内容推送,都带来App的一次卸载高峰? 同类活动那么多,怎样做才能超越竞品,占据头条? 为什么有的文案像“小广告”,有的文案像贴心老友? 创业公司与大平台的玩法有何不同? …… 如何从“了解运营”到“精通运营”,可能是运营人*的困惑。《超级运营术》正是对这个问题的全面解答。韩叙总结10年运营......一起来看看 《超级运营术》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具