首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何使一个方法仅在另一个方法可以被调用时才出现在“重载集中”?

如何使一个方法仅在另一个方法可以被调用时才出现在“重载集中”?
EN

Stack Overflow用户
提问于 2018-07-05 23:21:36
回答 1查看 227关注 0票数 1

考虑一下NotificationCenter上的一个扩展,它为符合某些协议的通知对象做了一些特殊的事情(是的,这些协议可能更常见,但这是一个帮助演示我真正的问题的示例)。

代码语言:javascript
运行
复制
extension NotificationCenter {

  func addObserver<Note: BasicNotification>(using block: @escaping (Note) -> ())
  -> NotificationToken {
    let observer = addObserver(forName: Note.notificationName, object: nil,
        queue: nil, using: { note in
      block(Note(notification: note))
    })
    return NotificationToken(observer: observer, center: self)
  }

  func addObserver<Note: CustomNotification>(using block: @escaping (Note) -> ())
  -> NotificationToken {
    let observer = addObserver(forName: Note.notificationName, object: nil,
        queue: nil, using: { note in
      block(note.object as! Note)
    })
    return NotificationToken(observer: observer, center: self)
  }

}

现在,考虑我们希望此通知只触发一次,然后取消注册...

代码语言:javascript
运行
复制
extension NotificationCenter {

  func observeOnce<Note: BasicNotification>(using block: @escaping (Note) -> ()) {
    var token: NotificationToken!
    token = addObserver(using: { (note: Note) in
      block(note)
      token.reset()
    })
  }

  func observeOnce<Note: CustomNotification>(using block: @escaping (Note) -> ()) {
    var token: NotificationToken!
    token = addObserver(using: { (note: Note) in
      block(note)
      token.reset()
    })
  }

}

这是完全相同的代码。我真正想要的是一个observeOnce方法--我不想写两个。

如果我不使用任何条件一致性...

代码语言:javascript
运行
复制
  func observeOnce<Note>(using block: @escaping (Note) -> ()) {
    var token: NotificationToken!
    token = addObserver(using: { (note: Note) in
      block(note)
      token.reset()
    })
  }

我得到了一个错误Cannot invoke 'addObserver' with an argument list of type '(using: (Note) -> ())',这是非常有意义的。

如果我使用一个通用的基础协议(两者都符合)...

代码语言:javascript
运行
复制
  func observeOnce<Note: SomeNotification>(using block: @escaping (Note) -> ()) {
    var token: NotificationToken!
    token = addObserver(using: { (note: Note) in
      block(note)
      token.reset()
    })
  }

我得到了完全相同的错误,这没有太多意义-我希望调用是模棱两可的,而不是根本不存在。

在看到&操作符意味着符合多个协议之后,我确实尝试过在极不可能的情况下使用BasicNotification | CommonNotification,因为这可能有一些意义……但它当然不起作用。

我还尝试了一堆其他的选择,但都没有用。我正在尝试做的是,如果其他任何一个可以调用,observeOnce都可以调用。

在C++中,我会这样做(没有通过编译器运行它--希望您能理解我想要做的事情)……

代码语言:javascript
运行
复制
template <typename T>
auto observeOnce(std::function<void (T)> block)
-> decltype(void(this->addObserver(std::move(block))))
{
  // do my stuff here
}

上面的代码基本上意味着,如果可以调用addObserver(std::move(block)),则仅在重载集中出现函数observeOnce

那么,完成同样的事情的快速方法是什么呢?

EN

回答 1

Stack Overflow用户

发布于 2018-07-11 22:52:05

你可以使用的一个技巧是重组你的代码。不是在NotificationCenter中创建多个(通用) addObserver方法,而是将它们移动到您的通知类型(基本通知和自定义通知)中,并使用协议将它们形式化。然后,您可以使用单个函数来扩展此协议,以添加addOnce逻辑。当您的基本通知和自定义通知实现此协议时,它们会自动继承此新的addOnce功能,而不需要任何重复的代码。

示例

这里有一个关于如何实现这个想法的例子:

首先,创建一个允许将观察者block添加到NotificationCenter的新协议ObservableNotification

代码语言:javascript
运行
复制
protocol ObservableNotification {
    static func addObserver(to center: NotificationCenter, using block: @escaping (Self)->Void) -> NotificationToken
}

然后,让您的通知协议继承此ObservableNotification协议

代码语言:javascript
运行
复制
protocol NameableNotification {
    static var notificationName: NSNotification.Name {get}
}

protocol CustomNotification: NameableNotification, ObservableNotification {}
protocol BasicNotification: NameableNotification, ObservableNotification {
    init(notification: Notification)
}

并使用协议扩展将您的addObserver方法(从NotificationCenter)移动到相应的协议作为默认实现:

代码语言:javascript
运行
复制
extension BasicNotification {
    static func addObserver(to center: NotificationCenter, using block: @escaping (Self)->Void) -> NotificationToken {
        let observer = center.addObserver(forName: Self.notificationName, object: nil, queue: nil) { note in
            block(Self(notification: note))
        }
        return NotificationToken(observer: observer, center: center)
    }
}

extension CustomNotification {
    static func addObserver(to center: NotificationCenter, using block: @escaping (Self)->Void) -> NotificationToken {
        let observer = center.addObserver(forName: Self.notificationName, object: nil, queue: nil) { note in
            block(note.object as! Self)
        }
        return NotificationToken(observer: observer, center: center)
    }
}

这样,您可以使用observeOnce方法的默认实现来扩展ObservableNotification协议,并且能够在符合ObservableNotification的每个类型上调用它(在本例中为CustomNotificationBasicNotification )。如下所示:

代码语言:javascript
运行
复制
extension ObservableNotification {
    static func addOneTimeObserver(to center: NotificationCenter, using block: @escaping (Self)->Void) -> NotificationToken {
        var token: NotificationToken!
        token = addObserver(to: center) {
            block($0)
            token.reset()
        }
        return token
    }
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51194950

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档