草庐IT

ios - 惰性/内联在 Swift 中实现协议(protocol)

coder 2023-07-17 原文

我想在 Swift 中延迟/内联实现一个协议(protocol)。
所以在实现的时候,我可以访问协议(protocol)范围之外的变量,

与在 Java 中实现接口(interface)而不声明类相同:

class MyClass:UIView {
  var someComponent:SomeInnerComponent = SomeInnerComponent();
  var count:Int = 0;

  var a = :SomeProtocol { //<----- IS THIS POSSIBLE, IF YES HOW ?
      func a0() {MyClass.count--}
      func a1() {MyClass.count++}
  } 

  someComponenet.delegate = a;
}

protocol SomeProtocol {
  func a0()
  func a1()
}

编辑----

谢谢我看这个解决方案,我没有看到如何访问父类的变量。
所有示例都显示了一个匿名类,但没有一个示例正在访问父变量。

最佳答案

您正在寻找的是一个内部类(不一定是匿名的),声明在一个允许它访问 count 的范围内。 MyClass 的变量实例,并且采用了在不同范围内定义的协议(protocol)。现在 Swift 有一些这样的部分,但看起来你不能以任何你可能想要的简洁的方式把它们放在一起。

你可能会考虑声明一个内部类:

class MyView: UIView {
    let someComponent = SomeInnerComponent() // type SomeInnerComponent is inferred
    var count = 0 // type Int is inferred
    class Helper: SomeProtocol {
        func a0() { count-- } // ERROR
        // ...
    }
    init() {
        someComponent.delegate = Helper()
    }
}

但这行不通,因为 count隐含 self.count , 其中 selfHelper实例,而不是 MyView “拥有” Helper 的实例实例。而且没有办法引用 MyView Helper 中的实例(或其属性)的方法,因为你也可以构造一个 MyView.Helper()没有现有的 MyView实例。 Swift 中的内部类(或一般的嵌套类型)仅嵌套在词法范围内,而不嵌套在存在所有权中。 (或者换一种说法,因为您引用了 Java:Swift 中的所有内部类都类似于 Java 中的静态内部类。没有非静态内部类。)但是,如果这是您想要的功能,it's probably worth telling Apple you want it .

您也可以尝试声明 Helper里面 MyView.init() -- 在 Swift 中,您可以在任何地方嵌套类型定义,包括内部函数或其他类型的方法。那里定义的,可以引用MyView的属性。但是,现在 Helper 的类型信息仅在 MyView.init() 内部可见, 所以当你把它分配给 someComponent.delegate (其类型只是 SomeProtocol ),你不能使用它......这甚至会使编译器崩溃。 (这是另一个 bug to report ,但很难说这个错误是真的“编译器在有效使用时崩溃”还是“代码不好,但编译器崩溃而不是产生错误”。)

我能想出的最接近的解决方案如下所示:
class SomeInnerComponent {
    var delegate: SomeProtocol?
}
protocol SomeProtocol {
    func a0()
    func a1()
}
class MyClass  {
    var someComponent = SomeInnerComponent()
    var count = 0
    struct Helper: SomeProtocol {
        var dec: () -> ()
        var inc: () -> ()
        func a0() { dec() }
        func a1() { inc() }
    }
    init() {
        someComponent.delegate = Helper(
            dec: { self.count -= 1 }, // see note below
            inc: { self.count += 1 }
        )
    }
}

这个怎么运作:
  • Helper是一个内部结构(可以是一个类,但结构更简单)
  • 它实现了 a0a1方法,满足SomeProtocol的要求
  • a0 的实现和 a1调用闭包decinc ,它们是 Helper 的存储属性(也称为实例变量)结构
  • 在构造 Helper 时编写(或以其他方式指定)这些闭包实例(使用默认的成员初始化器,Helper(dec: (Void -> Void), inc: (Void -> Void)))
  • 因为您可以在初始化 Helper 时编写闭包,这些闭包可以捕获您调用初始化程序的变量,包括隐式 self指的是 MyClass创建 Helper 的实例.

  • 你需要两个 a0/a1dec/inc因为您需要闭包(后者)而不是方法来捕获封闭状态。尽管闭包和函数/方法在许多方面是可以互换的,但您不能通过将闭包分配给方法/函数名称来创建方法/函数实现。 (如果 SomeProtocol 需要闭包属性而不是方法,那就另当别论了,但我假设 SomeProtocol 不在你的控制之下。)

    无论如何,这是一种您可能并不真正需要的大量样板和抽象层,因此可能值得研究其他方式来构建您的代码。

    注意:我的示例使用闭包 { self.count -= 1 }您可能期望的位置{ self.count-- } .后者不起作用,因为这是一个有值的表达式,所以 Swift 会将它解释为闭包返回值的简写。然后它会提示你分配了 () -> Int关闭期望 () -> () 的属性(又名 Void -> Void )关闭。使用 -= 1而是解决这个问题。

    关于ios - 惰性/内联在 Swift 中实现协议(protocol),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25704318/

    有关ios - 惰性/内联在 Swift 中实现协议(protocol)的更多相关文章

    1. ruby - 在 Ruby 中实现 `call_user_func_array` - 2

      我怎样才能完成http://php.net/manual/en/function.call-user-func-array.php在ruby中?所以我可以这样做:classAppdeffoo(a,b)putsa+benddefbarargs=[1,2]App.send(:foo,args)#doesn'tworkApp.send(:foo,args[0],args[1])#doeswork,butdoesnotscaleendend 最佳答案 尝试分解数组App.send(:foo,*args)

    2. ruby - 如何验证 IO.copy_stream 是否成功 - 2

      这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下

    3. ruby-on-rails - 如何在 Ruby on Rails 中实现无向图? - 2

      我需要在RubyonRails中实现无向图G=(V,E)并考虑构建一个Vertex和一个Edge模型,其中Vertex有_多条边。由于边恰好连接两个顶点,您将如何在Rails中执行此操作?您是否知道任何有助于实现此类图表的gem或库(对重新发明轮子不感兴趣;-))? 最佳答案 不知道有任何现有库在ActiveRecord之上提供图形逻辑。您可能必须实现自己的Vertex、EdgeActiveRecord支持的模型(请参阅Rails安装的rails/activerecord中的vertex.rb和edge.rb/test/fixtur

    4. Ruby 文件 IO 定界符? - 2

      我正在尝试解析一个文本文件,该文件每行包含可变数量的单词和数字,如下所示:foo4.500bar3.001.33foobar如何读取由空格而不是换行符分隔的文件?有什么方法可以设置File("file.txt").foreach方法以使用空格而不是换行符作为分隔符? 最佳答案 接受的答案将slurp文件,这可能是大文本文件的问题。更好的解决方案是IO.foreach.它是惯用的,将按字符流式传输文件:File.foreach(filename,""){|string|putsstring}包含“thisisanexample”结果的

    5. ruby-on-rails - 如何在 Ruby on Rails 中实现由 JSF 2.0 (Primefaces) 驱动的 UI 魔法 - 2

      按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭10年前。问题1)我想知道ruby​​onrails是否有功能类似于primefaces的gem。我问的原因是如果您使用primefaces(http://www.primefaces.org/showcase-labs/ui/home.jsf),开发人员无需担心javascript或jquery的东西。据我所知,JSF是一个规范,基于规范的各种可用实现,prim

    6. Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting - 2

      1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里

    7. ruby-on-rails - 创建 ruby​​ 数据库时惰性符号绑定(bind)失败 - 2

      我正在尝试在Rails上安装ruby​​,到目前为止一切都已安装,但是当我尝试使用rakedb:create创建数据库时,我收到一个奇怪的错误:dyld:lazysymbolbindingfailed:Symbolnotfound:_mysql_get_client_infoReferencedfrom:/Library/Ruby/Gems/1.8/gems/mysql2-0.3.11/lib/mysql2/mysql2.bundleExpectedin:flatnamespacedyld:Symbolnotfound:_mysql_get_client_infoReferencedf

    8. CAN协议的学习与理解 - 2

      最近在学习CAN,记录一下,也供大家参考交流。推荐几个我觉得很好的CAN学习,本文也是在看了他们的好文之后做的笔记首先是瑞萨的CAN入门,真的通透;秀!靠这篇我竟然2天理解了CAN协议!实战STM32F4CAN!原文链接:https://blog.csdn.net/XiaoXiaoPengBo/article/details/116206252CAN详解(小白教程)原文链接:https://blog.csdn.net/xwwwj/article/details/105372234一篇易懂的CAN通讯协议指南1一篇易懂的CAN通讯协议指南1-知乎(zhihu.com)视频推荐CAN总线个人知识总

    9. ruby - 为什么不能使用类IO的实例方法noecho? - 2

      print"Enteryourpassword:"pass=STDIN.noecho(&:gets)puts"Yourpasswordis#{pass}!"输出:Enteryourpassword:input.rb:2:in`':undefinedmethod`noecho'for#>(NoMethodError) 最佳答案 一开始require'io/console'后来的Ruby1.9.3 关于ruby-为什么不能使用类IO的实例方法noecho?,我们在StackOverflow上

    10. ruby - 在 Ruby 中实现 to_int 和 to_str 的后果 - 2

      我haveaclass它公开了一个字符串值和一个int值(分别是命令输出和退出代码)。除了通过to_s和to_i公开它们之外,我还使用to_str和to_int,如下所示:classStatusdefto_s@outputendalias:to_str:to_sdefto_i@status.exitstatusendalias:to_int:to_iend我的想法是能够在尽可能多的情况下使用这个对象。将其强制转换为字符串或整数会增加可用性。例如,我可以将对象与字符串连接起来:a_string="Outputwas:"+results(我想用这个作为int强制转换的例子,但是Fixnum

    随机推荐