我不知道是否可能,但我认为可以有办法做我想做的事。
我有以下情况:
enum ContactStatus: UInt {
case requestSent = 0, requestReceived, requestProcessing, active, removed
}
struct Contact {
var uid: String
var name: String?
var contactStatus: ContactStatus
init(uid: String, name: String? = nil, contactStatus: ContactStatus = .requestSent) {
self.uid = uid
self.name = name
self.contactStatus = contactStatus
}
}
class ContactStorage: {
private var contacts: [Contact]
init(contacts: [Contact]) {
contacts = contacts
}
func createContact(uid: String, contactStatus status: ContactStatus, name: String?) -> Contact {
var newContact = Contact(uid: uid)
newContact.contactStatus = status
newContact.name = name
newContacts.append(newContact)
return newContact
}
func updateContact(status: ContactStatus, peerUId: String) {
for (index, _) in contacts.enumerated() {
if contacts[index].uid == peerUId {
contacts[index].contactStatus = status
return
}
}
}
func updateContact(name: String, peerUId: String) {
for (index, _) in contacts.enumerated() {
if contacts[index].uid == peerUId {
contacts[index].name = name
return
}
}
}
}
正如我们所看到的,
ContactStorage
有两种方法来更新联系人状态和姓名。类似:
func updateContact<T: Updateable>(peerUId: String, updatableProperty: T) {
//implementation
}
是否可以只写一个方法而不是两个?
你可以“有点”用闭包来做到这一点。
“XXX”和“YYY”部分是您所拥有的两种方法之间唯一不同的部分:
for (index, _) in contacts.enumerated() {
if contacts[index].uid == peerUId {
contacts[index].XXX = YYY
return
}
}
因此,如果我们想将其提取为方法,我们需要一个闭包作为参数来提供“XXX”部分。
该闭包可以如下所示:
(inout Contact, T) -> Void
对于“YYY”部分,常规参数就可以了。
因此,该方法如下所示:
func updateProperty<T>(property: (inout Contact, T) -> Void, value: T, peerUId: String) {
for (index, _) in contacts.enumerated() {
if contacts[index].uid == peerUId {
property(&contacts[index], value)
return
}
}
}
你可以这样称呼它:
updateProperty(property: {$0.name = $1}, value: "Tom", peerUId: "something")
另一种方法是完全删除“YYY”,并将其集成到闭包中:
func updateProperty(property: (inout Contact) -> Void, peerUId: String) {
for (index, _) in contacts.enumerated() {
if contacts[index].uid == peerUId {
property(&contacts[index])
return
}
}
}
用途:
updateProperty(property: {$0.name = "Tom"}, peerUId: "something")
不需要通用函数。您应该让
updateContact
有 3 个输入参数:peerUId
、name
和 status
,并将后两个设置为具有 nil
默认值的可选参数。这样,您可以使用单个函数调用来更新 name
和 status
,如果您只想更新其中一个,则只需不为另一个指定输入值即可。
func updateContact(peerUId: String, status: ContactStatus? = nil, name: String? = nil) {
if status == nil, name == nil { return } //wrong function call, return
for i in 0..<contacts.count {
if contacts[i].uid == peerUId {
if let newStatus = status {
contacts[i].contactStatus = newStatus
}
if let newName = name {
contacts[i].name = newName
}
}
}
}
您可以这样调用该函数:
updateContact(peerUId: "value", status: ContactStatus.active) //only updates the contactStatus
updateContact(peerUId: "value", name: "John") //only updates the name
updateContact(peerUId: "value", status: ContactStatus.active, name: "John") //updates both in a single function call
我知道这是一篇非常旧的帖子,但是在寻找答案时,我碰巧偶然发现了这个问题,并找到了一些实现来创建“可更新”协议。
协议定义 -
protocol UpdatableProperties {}
protocol Updatable {
associatedtype Property: UpdatableProperties
func update(property: Property)
}
像这样使用这些协议 -
enum ObjectUpdatableProperties: UpdatableProperties {
case name(name: String)
case phoneNumber(phoneNumber: String)
case email(email: String)
}
class UpdatableObject: Updatable {
private(set) var userId: String
private(set) var userEmail: String?
private(set) var name: String?
private(set) var phoneNumber: String?
init(userId: String, userEmail: String? = .none, name: String? = .none, phoneNumber: String? = .none) {
self.userId = userId
self.userEmail = userEmail
self.name = name
self.phoneNumber = phoneNumber
}
func update(property: ObjectUpdatableProperties) {
switch property {
case .name(let name):
self.name = name
case .phoneNumber(let phoneNumber):
self.phoneNumber = phoneNumber
case .email(let email):
self.userEmail = email
}
}
}
使用-
var updatableObj = UpdatableObject(userId: "userId", userEmail: "[email protected]", name: "My Name Is Me", phoneNumber: .none)
updatableObj.update(property: .phoneNumber(phoneNumber: "A real phone number!"))
希望这对某人有帮助...