【问题标题】:Trying to implement publisher/subscriber in swift尝试快速实现发布者/订阅者
【发布时间】:2016-02-16 10:43:03
【问题描述】:

我实际上是在尝试在我的 Swift 项目中实现 pub/sub 模式,我几乎没有执行任务的 代理 (Singletons),当他们的状态发生变化时,他们应该通知所有之前订阅的监听器。

我收到了设置我的协议的错误,可能它应该符合Equatable 协议,但我看不出是哪种方式(声明protocol AvailableChatListener: Equatable 解决不了任何问题)。

我知道我可以使用 Apple 的 NSNotificationCenter(也可以使用 here),但这不是一个完全适合我要求的解决方案。

代码如下:

AvailableChatListener.swift

protocol AvailableChatListener {
    func onAvailableChatChange()
}

AvailableChatAgent.swift

class AvailableChatAgent {
  // MARK: - Singleton

  class var sharedInstance: AvailableChatAgent {
    struct Singleton {
      static let instance = AvailableChatAgent()
    }
    return Singleton.instance
  }

  // MARK: - Listeners

  private var availableChatListeners = [AvailableChatListener]()

  // MARK: - Public Properties

  // current Chats
  var currentChats = [Chat]()   {
    didSet  {
      statusChanged()
    }
  }

  func startObserving()   {
    // ...
    // perform tasks and change currentChats
    // ...
  }

  func stopObserving()    {
    // ...
    // stop tasks
    // ...
  }

  func statusChanged()    {

    // notify listeners
    for receiver in availableChatListeners {
      receiver.onAvailableChatChange()
    }
  }

  // ERROR #1
  func subscribeListener(listener: AvailableChatListener)    {
    availableChatListeners.append(listener)
  }

  // ERROR #1
  func unsubscribeListener(listener: AvailableChatListener)  {

    // ERROR #2
    if let index = availableChatListeners.indexOf(listener) {
      availableChatListeners.removeAtIndex(availableChatListeners.indexOf(listener)!)

      if availableChatListeners.count == 0 {
        self.stopObserving()
      }
    }
  }
}

我在这里使用这个逻辑(例如在 TableViewController 中)

ChatListTableViewController.swift

class ChatListTableViewController: UITableViewController, AvailableChatListener {

  // MARK: - Properties

  var availableChatAgent = AvailableChatAgent.sharedInstance

  // MARK: - ViewDidLoad

  override func viewDidLoad() {
    super.viewDidLoad()

    availableChatAgent.subscribeListener(self)
  }

  // MARK: - Implement AvailableChatListener

  func onAvailableChatChange()    {
    // perform task with the new data, for example update UI
  }
}

提前致谢。

更新 1

我得到的错误:

  1. protocol "AvailableChatListener' can only be used as a generic constraint because it has Self or associated type requirements
  2. Cannot convert value of type 'AvailableChatListener' to expect argument type '@noescpae(AvailableChatListener) throws -> Bool'

【问题讨论】:

  • 你得到什么错误?
  • 我会为你的听众使用一个集合而不是一个数组并实现 Hashable 协议
  • @PradeepK 这是我得到的错误:protocol "AVailableChatListener' can only be used as a generic constraint because it has Self or associated type requirementsCannot convert value of type 'AvailableChatListener' to expect argument type '@noescpae(AvailableChatListener) throws -> Bool。现在我更新问题。 @Paulw11 现在我尝试使用 Set 而不是 Array,如何实现 Hashable 协议?
  • 其实我认为你不需要为集合成员实现 Hashable

标签: ios xcode swift publish-subscribe


【解决方案1】:

请尝试这种删除监听器的方法,看看它是否有效。我已将对象转换为 NSArray,然后在该数组中查找侦听器的索引。我假设两个听众是相同的,如果他们是同一个对象而不是任何其他条件。

func unsubscribeListener(listener: AvailableChatListener)  {
    let arr = availableChatListeners as NSArray
    let index = arr.indexOfObject(listener)
    if index != NSNotFound {
        availableChatListeners.removeAtIndex(index)
        if availableChatListeners.count == 0 {
            self.stopObserving()
        }
    }
}

你也应该这样声明你的协议(添加@objc)

@objc protocol AvailableChatListener  {
    func onAvailableChatChange()
}

【讨论】:

  • 很好,这实际上解决了我与func unsubscribeListener 的问题。 func subscribeListeneravailableChatListener 声明的问题仍然存在(如 @Paulw11 所述,我使我的协议符合 Hashable ,但声明时出现错误:Using 'LocationListener' as a concrete type coforming to Protocol 'Hashable' is not supported)。我该如何解决这个问题?
  • 我忘了提到对协议的更改。我已经更新了答案。不确定这是否会解决您的第二个问题。有了更新的答案,我在您提到的地方没有收到错误
【解决方案2】:

我遇到了同样的问题,并执行了以下操作来解决它。使用 Objective-C Sets 需要使用基于 NSObject 的订阅者来解决上面提到的哈希问题。

import UIKit

protocol LogoListener {
    func logo(urlString url: String, hasImage image: UIImage)
}

class Server {
    var logoListeners = NSMutableSet()
    func addListener(listener: LogoListener) {
        logoListeners.add(listener)
        print("Added listener \(listener)")
    }
}

class Registration: NSObject, LogoListener {
    func logo(urlString url: String, hasImage image: UIImage) {
        savedImage = image
    }
    var savedImage: UIImage = UIImage()
    override init() {
        super.init()
        let server = Server()
        server.addListener(listener: self)
    }
}

let reg = Registration()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-14
    • 1970-01-01
    • 2021-07-28
    • 1970-01-01
    相关资源
    最近更新 更多