swift我应该使用协议还是协议:class

时间:2016-10-19 22:35:41

标签: swift swift-protocols

我已经设置了一个协议,将一些信息发送回上一个VC。

我这样定义:

protocol FilterViewControllerDelegate: class  {
    func didSearch(Parameters:[String: String]?)
}

但使用时有什么区别:

protocol FilterViewControllerDelegate  {
        func didSearch(Parameters:[String: String]?)
    }

我什么时候应该使用: class协议?

5 个答案:

答案 0 :(得分:45)

Swift 4版本

AnyObject添加到像这样的协议定义

protocol FilterViewControllerDelegate: AnyObject  {
    func didSearch(parameters:[String: String]?)
}

表示只有一个类能够符合该协议。

所以给出了这个

protocol FilterViewControllerDelegate: AnyObject  {
    func didSearch(parameters:[String: String]?)
}

你可以写这个

class Foo: FilterViewControllerDelegate {
    func didSearch(parameters:[String: String]?) { }
}

但是这个

struct Foo: FilterViewControllerDelegate {
    func didSearch(parameters:[String: String]?) { }
}

Swift 3版本

:class添加到像这样的协议定义

protocol FilterViewControllerDelegate: class  {
    func didSearch(Parameters:[String: String]?)
}

表示只有一个类能够符合该协议。

所以给出了这个

protocol FilterViewControllerDelegate: class  {
    func didSearch(Parameters:[String: String]?)
}

你可以写这个

class Foo: FilterViewControllerDelegate {
    func didSearch(Parameters:[String: String]?) { }
}

但是这个

struct Foo: FilterViewControllerDelegate {
    func didSearch(Parameters:[String: String]?) { }
}

答案 1 :(得分:16)

还有一个关于使用'标记协议的另一个问题是'关键字。

这是你的协议:

#to check that the target has loaded its images, run images loaded
#after a small timeout to allow the page to get the images
#append a marker div to the dom if the images have successfully loaded
imagesLoadedScript = "var item = document.querySelector('#{csspath}');
                      window.scroll(0, item.offsetTop);
                      function imagesDone(path, fn) {
                        imagesLoaded( path, function(instance) {
                           console.log('PHANTOM CLIENT REPORTING: ' + path + ' Images Loaded');
                           fn(true);
                        })
                      }
                      setTimeout(function(){ 
                         imagesDone('#{csspath}', function(done) { 
                           var markerDiv = document.createElement('div'); 
                           markerDiv.id = 'ImagesLoadedMarker'; 
                           document.getElementsByTagName('html')[0].appendChild(markerDiv); 
                         });
                      }, 1000)"

#then we strip the new lines and spaces that we added to make it readable 
imagesLoadedScript = imagesLoadedScript.strip.gsub(/\s+/,' ')
#now we just execute the script as we do not need a return value
@session.execute_script(imagesLoadedScript)
#then we check for the marker, using capybara's inbuilt waiting time
if @session.has_xpath? "//*[@id ='ImagesLoadedMarker']"
   Rails.logger.debug "!!!!! PhantomClient: Images Loaded Reporting: #{csspath} Images Loaded: Check Time #{Time.now} !!!!!"
   @session.save_screenshot(file_path, :selector => csspath)
else
   Rails.logger.debug "!!!!! PhantomClient: Images Loaded Reporting: #{csspath} Images NOT Loaded: Check Time #{Time.now} !!!!!"
   @session.save_screenshot(file_path, :selector => csspath)
end

例如,我们假设您正在创建一个具有委托属性的DetailVC:

protocol FilterViewControllerDelegate: class  {
    func didSearch(Parameters:[String: String]?)
}

如果你没有用“课程”标记该协议。关键字,您也无法标记该代表'作为“弱者”的财产之一。

为什么?

这很简单 - 只有基于类的属性可能会有弱关系。 如果你试图避免参考周期,那就是要走的路了

答案 2 :(得分:7)

Swift 4.2,Xcode 10语法:

protocol FilterViewControllerDelegate: AnyObject {
       func didSearch(Parameters:[String: String]?)
}

该协议只能由类采用。

回答您的第一个问题 -

  

但使用时有什么区别:

与此不同的是:

protocol FilterViewControllerDelegate  {
        func didSearch(Parameters:[String: String]?)
}

是该协议可以采用值类型,例如枚举和结构。

回答您的第二个问题 -

  

我什么时候应该使用:class protocal?

当您应该使用类协议时,我想从委托模式描述下一个示例: 想象一下,你有委托协议。

protocol PopupDelegate: AnyObject {
    func popupValueSelected(value: String)
}

并在另一个类中创建属性

var delegate: PopupDelegate?

但这有一个强大的参考,可以带来内存泄漏的问题。修复内存泄漏的一种方法是使委托属性 - 弱。在我们不能使我们的协议仅用于申请课程之前,Swift认为我们也可以将我们的协议应用于价值类型。

weak var delegate: PopupDelegate?

如果您尝试将您的委托声明为弱,则会看到下一个错误:

  

'weak'var仅适用于类和类绑定协议类型,   不是'PopupDelegate'

但是我们不能将弱值应用于值类型。所以我们需要将协议限制为引用类型,因此swift知道它是一个引用类型。 为了使您可以将此委托声明为弱,您需要限制仅由类使用的协议:

protocol PopupDelegate: AnyObject {
    func popupValueSelected(value: String)
}

答案 3 :(得分:5)

这意味着您定义的协议只能通过类,而不是结构或枚举来使用。

来自Official Swift book

protocol SomeClassOnlyProtocol: class, SomeInheritedProtocol {
    // class-only protocol definition goes here } 
  

在上面的示例中,SomeClassOnlyProtocol只能由类类型采用。它是   编写结构或枚举定义的编译时错误   试图采用SomeClassOnlyProtocol。

答案 4 :(得分:1)

Swift 3.2更新:

现在声明只有类协议写:

protocol SomeClassOnlyProtocol: AnyObject, SomeInheritedProtocol {
    // class-only protocol definition goes here
}

而不是

protocol SomeClassOnlyProtocol: class, SomeInheritedProtocol {
    // class-only protocol definition goes here
}

第二个片段现在似乎仍然有用。 参考:https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html