美文网首页
Swift:Candidate is not '@objc',b

Swift:Candidate is not '@objc',b

作者: JWeee | 来源:发表于2016-07-30 14:04 被阅读0次

案例

class ExamMenu: NSObject {

}

extension ExamMenu: UITableViewDataSource {
    
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 2
    }
    
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell:UITableViewCell! = tableView.dequeueReusableCellWithIdentifier("UITableViewCell")
        cell.contentView.backgroundColor = .lightGrayColor()
        return cell
    }

}

上面的代码是在swift中实现一个UITableViewDataSource的典型代码,按照上面的书写方式,一切正常,编译器不会报错。但有这时候我们想给ExamMenu添加access level,把它设置为内部私有的,我们把class的定义改成了下面的写法:

private class ExamMenu: NSObject {

}

error.png

这时我们看到编译器给我们报错了:Candidate is not '@objc',but protocol requires it,意思是协议要求方法采用@objc修饰。我们按照编译器提示,在协议方法前面加上@objc修饰,错误消失了。

extension ExamMenu: UITableViewDataSource {
    
    @objc func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 2
    }
    
    @objc func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell:UITableViewCell! = tableView.dequeueReusableCellWithIdentifier("UITableViewCell")
        cell.contentView.backgroundColor = .lightGrayColor()
        return cell
    }

}

分析

我们知道,为方法添加上@objc修饰之后,表明该方法可能被OC的调用,OC的方法调最终会编译成objc_msgSend方法调用,基于动态的方式去查找方法。为了提高性能,swift的方法调用是静态调用方式,所以swift中的方法如果不加任何表明,就不能给OC的runtime查找到,采用@objc修饰也就是建议编译器将该方法放入动态查找列表(但编译器可能会做优化,而没有这么做),好让OC能够动态查找到该方法。

回到刚才的案例中,我们还有个疑问:为什么在给class加上private修复之前,编译器没有报错?

这里是因为ExamMenu继承自NSObject,编译器会其自动为所有的非private成员加上@objc修饰,而如果给class加上了private修饰,其成员默认就是private访问控制权限,就缺少了@objc的修饰,就需要我们手动添加上。

dynamic修饰符

swift中dynamic修饰符也是为了告诉编译器,方法可能被动态调用,需要将其添加到查找表中,所以,将代码按照如下修改,也可以解决编译器报错的问题。

extension ExamMenu: UITableViewDataSource {
    
    dynamic func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 2
    }
    
    dynamic func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell:UITableViewCell! = tableView.dequeueReusableCellWithIdentifier("UITableViewCell")
        cell.contentView.backgroundColor = .lightGrayColor()
        return cell
    }

}

相关文章

网友评论

      本文标题:Swift:Candidate is not '@objc',b

      本文链接:https://www.haomeiwen.com/subject/cbftsttx.html