除了它们引用的几个变量名称外,我还有一些基本相同的功能。我想对函数进行抽象,这样就不必重复复制代码。这是一个示例函数:
func listenToParticipantNumber() {
guard let reference = participantNumberReference else {
return
}
guard participantNumberListener == nil else {
return
}
participantNumberListener = backendClient.listenToRtdbProperty(reference) { [weak self] (result: Result<Int, RequestError>) in
guard let strongSelf = self else {
return
}
switch result {
case .success(let participantNumber):
strongSelf.participantNumber = participantNumber
case .failure:
break
}
}
}
在另一个函数中,我将participantNumberReference
,participantNumber
和participantNumberListener
切换为不同的变量(它们对我的班级都是私有的),并且块返回类型为{ {1}}。但是该功能的核心布局是相同的。
如何使此过程更干净以重用此代码,而不必重复代码?是否可以以某种方式使用Int
来引用我班上的不同变量?
答案 0 :(得分:0)
要达到此抽象级别,需要大量的准备工作,因此您必须提出更大的问题,以了解您真正在尝试做什么以及值得这样做,但这是一个概述。本质是使用具有属性的字典,而不是显式声明的变量。
现在,您可以将未来的案例添加到PersonType
中并对其进行初始化(可能是自动化的),并且该函数将适用于所有案例。可以想象将PersonType
声明在类之外以增加分隔。
这可能更适合代码审查,您可以在其中发布更多上下文。
enum PersonType { case Participant, case Leader, case Observer }
struct TrackedObject { var number: Int; var numberReference: ReferenceProtocol; var numberListener: ListenerProtocol; }
// Instead of 9 private variables, make a Dictionary of 3 objects each of
// which have 3 properties
private var persons: [ PersonType: TrackedObject ] = ...
func listenToPersonOfType(personType: PersonType) {
guard let reference = persons[personType].numberReference else {
return
}
guard persons[personType].numberListener == nil else {
return
}
persons[personType].numberListener = backendClient.listenToRtdbProperty(reference) { [weak self] (result: Result<Int, RequestError>) in
guard let strongSelf = self else {
return
}
switch result {
case .success(let number):
strongSelf.persons[personType].number = number
case .failure:
break
}
}
}
答案 1 :(得分:0)
我认为您在使用KeyPath的道路上正确。我可能会对此进行一些重构,以便listen
方法返回Listener?
(无论是哪种类型),并在此之外提升“如果已经设置了侦听器,请不要这样做”。功能。
这将使您遵循以下原则:
func listen<Response>(reference: Int?, // Or whatever type this is
updating keyPath: WritableKeyPath<C, Response>,
completion: (Result<Response, Error>) -> Void) -> Listener? {
guard let reference = reference else { return nil }
return backendClient.listenToRtdbProperty(reference) { [weak self] (result: Result<Response, Error>) in
guard var strongSelf = self else {
return
}
switch result {
case .success(let result):
strongSelf[keyPath: keyPath] = result
case .failure:
break
}
}
或者您可以通过以下方式保留现有结构:
func listen<Response>(reference: Int?,
updating keyPath: WritableKeyPath<C, Response>,
forListener listener: WritableKeyPath<C, Listener?>,
completion: (Result<Response, Error>) -> Void) {
guard let reference = reference else { return }
guard self[keyPath: listener] == nil else {
return
}
var mutableSelf = self
mutableSelf[keyPath: listener] = backendClient.listenToRtdbProperty(reference) { [weak self] (result: Result<Response, Error>) in
guard var strongSelf = self else {
return
}
switch result {
case .success(let result):
strongSelf[keyPath: keyPath] = result
case .failure:
break
}
}
}
(所有这些代码中的C
都是“此类”。我们还不能写Self
来表示“当前类”。)
答案 2 :(得分:0)
所以我这样解决了:
stack script
我实际上是在Rob回答之前完成此操作的,但是我必须使用#!/usr/bin/env stack
{-
stack script
--resolver lts-13.14
--package turtle
-}
main = print "hello"
,因为使用private func listen<T>(
to property: ReferenceWritableKeyPath<LivestreamModel, T?>,
withReference propertyReference: ReferenceWritableKeyPath<LivestreamModel, String?>,
listener: ReferenceWritableKeyPath<LivestreamModel, DatabaseHandle?>) {
guard let reference = self[keyPath: propertyReference] else {
return
}
guard self[keyPath: listener] == nil else {
return
}
self[keyPath: listener] = backendClient.listenToRtdbProperty(reference) { [weak self] (result: Result<T, RequestError>) in
switch result {
case .success(let value):
self?[keyPath: property] = value
case .failure:
self?[keyPath: property] = nil
}
}
}
时,它会警告ReferenceWritableKeyPath
没有下标成员。