在Swift中更新不同数据类型属性的通用方法

时间:2017-09-11 15:23:46

标签: swift generics

我不知道是否可能,但我认为可以有办法做我想做的事。
我有以下情况:

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
}

是否可以只编写一种方法而不是两种方法?

2 个答案:

答案 0 :(得分:1)

你可以通过闭包来“做到”。

“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")

答案 1 :(得分:0)

不需要通用功能。您应该让updateContact有3个输入参数:peerUIdnamestatus,并将后两个设置为具有nil默认值的选项。这样,您可以使用单个函数调用更新namestatus,如果您只想更新其中一个,则不要为另一个指定输入值。

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