Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 使用关联类型快速收集符合协议的对象_Ios_Swift_Protocols_Type Erasure_Swift4 - Fatal编程技术网

Ios 使用关联类型快速收集符合协议的对象

Ios 使用关联类型快速收集符合协议的对象,ios,swift,protocols,type-erasure,swift4,Ios,Swift,Protocols,Type Erasure,Swift4,我可能有一个关于类型擦除的问题。想象一下以下场景: public protocol DataItem { associatedtype T var action: ((_ item: T) -> Void)? {get} } struct UserItem: DataItem { typealias T = UserItem // Custom Properties let name: String // Protocol: Dat

我可能有一个关于类型擦除的问题。想象一下以下场景:

public protocol DataItem {

    associatedtype T
    var action: ((_ item: T) -> Void)? {get}
}

struct UserItem: DataItem {

    typealias T = UserItem

    // Custom Properties
    let name: String

    // Protocol: DataItem
    let action: ((T) -> Void)?
}

struct DriverItem: DataItem {

    typealias T = DriverItem

    // Custom Properties
    let licenseNumber: String

    // Protocol: DataItem
    let action: ((T) -> Void)?
}

let items = [
    UserItem(name: "Dexter", action: { (item) in print(item.name)}),
    DriverItem(licenseNumber: "1234567890", action: { (item) in print(item.licenseNumber)})
]

items.forEach {
    $0.action?($0)
}
我有一个DataItem,它是UITableViewCell的一个抽象数据项,它有一个action属性,在选择单元格时应该调用该属性。我的问题是如何创建一个DataItem对象数组,从列表中选择一个项目,或者迭代该项目并调用相应的操作,该操作将打印UserItem的名称和DriverItem的许可证号。但是在上面的实现中,编译器会用以下消息抱怨条目列表只能是[Any]类型

异类集合文字只能推断为“[任何]”;如果有意这样做,请添加显式类型注释

这样我就不能调用协议数据项中声明的操作。我试图把我的头缠在字型擦除上,但还不能理解它


如果有人能想出一个解决方案,我会很高兴…

没有额外的要求,这并不难:

struct UserItem {
    let name: String

    func action() {
        print(name)
    }
}

struct DriverItem {
    let licenseNumber: String

    func action() {
        print(licenseNumber)
    }
}

let data = UserItem(name: "Test")
let closure = { print("Some object data \(data.name)") }
let items = [
    UserItem(name: "Dexter").action,
    DriverItem(licenseNumber: "1234567890").action,
    closure
]

items.forEach {
    $0()
}

该错误仅要求您向项目添加类型:

let items: Array<Any> = [
    UserItem(name: "Dexter", action: { (item) in print(item.name)}),
    DriverItem(licenseNumber: "1234567890", action: { (item) in print(item.licenseNumber)})
]
该数组将变成如下所示:

let items: Array<Any> = [
    UserItem(name: "Dexter"),
    DriverItem(licenseNumber: "1234567890")
]

动作闭包被认为是一个可以从外部设置的闭包,而不是一个静态函数。你可以将任何具有正确签名的闭包放入数组中-你不能让闭包使用不同的参数。您还可以将带有标题示例和void闭包的结构放在适当的数组中。仍然无法调用类似items.forEach{$0.action?$0}的操作方法,因为items包含您案例中的任何对象。我想我搜索的是类型橡皮擦模式,但我不确定如何正确实现它。@blackjacx如果let item=$0 as,我会这样做吗?UserItem{item.actionitem}与其浪费大量时间尝试解决它,不如在UserItem/DriverItem/is UserItem/DriverItem/is中关联类型,这看起来有点奇怪,这意味着实例闭包操作采用与拥有它的实例相同类型的单个参数。例如,给定的UserItem实例将对UserItem的另一个实例执行操作,这是否符合预期?我希望在实例本身而不是次要外部实例上执行操作,但这可能是一个预期的设计选择。无论如何,如果是这样,您可以松开associatedtype,只使用Self而不是T。它与uicontrol中的目标/操作类似,用于在操作方法中提供发送者。发送者就是项目本身。我希望通过这种方式,可以在action方法中使用具体类型的功能,如name和licenseNumber,你知道吗?重要的是,这些项只存在于不知道具体类型的DataSource对象中。这就是我无法直接访问具体类型功能的原因。我会尽快尝试你的方法。非常感谢:-Arg。。。。使用Self而不是T的行为相同:协议“DataItem”只能用作泛型约束,因为它具有Self或关联的类型要求。由于这种行为类型的橡皮擦被写入。但我不知道如何正确地做。。。有人有主意吗?
let items: Array<Any> = [
    UserItem(name: "Dexter"),
    DriverItem(licenseNumber: "1234567890")
]