【问题标题】:Creating an array of @objc protocol type from arrays of conformers从一致性数组创建一个 @objc 协议类型数组
【发布时间】:2015-01-26 13:54:54
【问题描述】:

我尝试了很多方法,但无论我做什么,快速编译器都会抱怨。 SourceKit 和编译器也不停地崩溃,所以我什至不能再试验了。甚至不插入一些printlns。我在扯头发。

我正在尝试为表格视图内容构建一个简单的数组。 “行”是Presentable 对象,它只是协议的集合。

import Foundation

// The protocols are all @objc
typealias Presentable = protocol<Utterable, Displayable, Departure>
typealias TableSection = (sectionTitle: String, rows: [Presentable])

1.这不起作用:

buses, metros 等都是[Bus]?, [Metro]? 等,并且这些类符合Presentable 的所有协议)

private func asContent5() -> [TableSection]
{
    var result: Array<TableSection> = []

    var deptsCollections: [[Presentable]?] = [ buses, metros, trains, trams, ships ]
    for var i = 0; i<deptsCollections.count ; i++ {
        if let departures = deptsCollections[i]? {
            var newDeparturesArray: [Presentable] = []
            for dep in departures
            {
                newDeparturesArray.append(dep) // EXC_BAD_INSTRUCTION
            }
            let tuple: TableSection = (sectionTitle: "test", rows: newDeparturesArray)
            result.append(tuple)
        }
    }
    return result
}

控制台输出:

fatal error: NSArray element failed to match the Swift Array Element type

2。这个“有效”(即在运行时不会崩溃)但我的新数组中似乎没有对象:

private func asContent4() -> [TableSection]
{
    var result: Array<TableSection> = []

    var deptsCollections: [AnyObject?] = [ buses, metros, trains, trams, ships ]
    for var i = 0; i<deptsCollections.count ; i++ {
        if let departures: [Presentable] = deptsCollections[i] as? [Presentable] {
            var newDeparturesArray: [Presentable] = []
            for dep in departures
            {
                newDeparturesArray.append(dep as Presentable)
            }
            let tuple: TableSection = (sectionTitle: "test", rows: newDeparturesArray)
            result.append(tuple)
        }
    }
    return result
}

3.这完全有效:

private func asContent3() -> [TableSection]
{
    var result: Array<TableSection> = []

    if let departures = buses {
        var newDeparturesArray: [Presentable] = []
        for dep in departures { newDeparturesArray.append(dep as Presentable) }
        let tuple: TableSection = (sectionTitle: "bus", rows: newDeparturesArray)
        result.append(tuple)
    }

    if let departures = metros {
        var newDeparturesArray: [Presentable] = []
        for dep in departures { newDeparturesArray.append(dep as Presentable) }
        let tuple: TableSection = (sectionTitle: "metro", rows: newDeparturesArray)
        result.append(tuple)
    }

    if let departures = trains {
        var newDeparturesArray: [Presentable] = []
        for dep in departures { newDeparturesArray.append(dep as Presentable) }
        let tuple: TableSection = (sectionTitle: "trains", rows: newDeparturesArray)
        result.append(tuple)
    }

    if let departures = trams {
        var newDeparturesArray: [Presentable] = []
        for dep in departures { newDeparturesArray.append(dep as Presentable) }
        let tuple: TableSection = (sectionTitle: "trams", rows: newDeparturesArray)
        result.append(tuple)
    }

    if let departures = ships {
        var newDeparturesArray: [Presentable] = []
        for dep in departures { newDeparturesArray.append(dep as Presentable) }
        let tuple: TableSection = (sectionTitle: "ships", rows: newDeparturesArray)
        result.append(tuple)
    }

    return result
}

我想要的只是把我的buses, metros, trains, trams, ships 放在一个[Presentable] 中,没有代码墙。我开始相信这在 Swift 中是不可能的,因为感觉就像我以各种可能的方式重写了这些循环。

我错过了什么?为什么我似乎无法成功迭代而不是重复所有这些代码?


更新

这就是 Davids 代码发生的情况:

与上面相同的控制台输出,但这次它在尝试访问 TableSection::rows 时崩溃(我以前也发生过这种情况)。这使它崩溃:

println("index path s: \(indexPath.section) r: \(indexPath.row)")
let section = tableContent[indexPath.section]
println("row count: \(section.rows.count)")
let departure: Presentable = section.rows[indexPath.row] // crash

控制台(我从变量视图打印了rows 数组):

index path s: 0 r: 0
row count: 8
fatal error: NSArray element failed to match the Swift Array Element type
Printing description of section.rows:
([protocol<Departure, Displayable, Utterable>]) rows = {}

只有我一个人,还是这些数字不加起来?

【问题讨论】:

  • 原因可能在这里解释:stackoverflow.com/questions/24113354/…var deptsCollections: [[Presentable]?] = [ buses ] 中的数组桥接不起作用
  • 可能是。我已经能够分配var myPresentables: [Presentable]? = buses。我知道这是一个可疑的分配,因为数组的类型是 [Bus] 而不是 [Presentable],但我不确定这是否重要。它破坏了类型安全,但它编译并且只要它是一个 [@objc 协议] 就可以工作......

标签: arrays swift protocols swift-protocols


【解决方案1】:

在生成了这里缺少的一堆代码后,我想出了以下内容,似乎可以按您的预期工作:

import Foundation

@objc protocol Utterable {}
@objc protocol Displayable {}
@objc protocol Departure {}

typealias Presentable = protocol<Utterable, Displayable, Departure>
typealias TableSection = (sectionTitle: String, rows: [Presentable])

class Bus : Presentable {}
class Metro : Presentable {}
class Train : Presentable {}
class Tram : Presentable {}
class Ship : Presentable {}

let buses : [Bus]? = nil
let metros : [Metro]? = [ Metro() ]
let trains : [Train]? = [ Train() ]
let trams : [Tram]? = nil
let ships : [Ship]? = [Ship()]

let departments : [[Presentable]?] = [ buses, metros, trains, trams, ships]

// filter out the non-nil departments that actually have elements
let acceptable = departments.filter { $0?.count > 0 }

// map the acceptable departments into sections, note that we force-unwrap
//  dept because we already verified in the step above that it must be
//  valid
let sections : [TableSection] = acceptable.map { (sectionTitle:"test", rows: $0!) }

请注意,这使用了两个非常重要的内置函数 filtermap 我建议深入研究它们,因为它们加上 reduce 是非常强大的内置函数,几乎无需手动操作做你自己的数组迭代。

或者,为了紧凑,您可以使用:

// or for compactness...
let sections2 : [TableSection] = departments.filter({ $0?.count > 0 })
                                            .map({ (sectionTitle:"test", rows: $0!) })

【讨论】:

  • 我喜欢这种方法,并尝试了您的代码。它似乎没有完全工作:/开始怀疑这是因为 swift 的扩展系统损坏(请参阅我的另一个问题:stackoverflow.com/q/28131121/220820
  • 抱歉缺少代码。添加它是不切实际的,因为有一个带有基类的层次结构,并且每个协议至少有一个扩展来保持整洁。有时我可以通过将协议的采用从扩展转移到类来避免运行时错误(即class A : B而不是extension A : B。这很奇怪。
  • 听起来你需要为你的问题添加更多信息,因为那里没有提到扩展名:)
  • 嗯...当我将协议合规性放入扩展程序中时,我得到一个崩溃“方法崩溃损坏”对我来说这听起来像是一个真正的 Apple 错误,因为它看起来确实像一个内部错误,应该永远不会被看到。我建议将合规性从扩展移到类中,并将错误提交给bugreporter.apple.com
  • 好吧,如果您采用上述内容并将合规性拆分为单独的扩展(仍然什么都不做),那么您在其他错误中报告的问题会重现。如果这样做可以解决您在此处报告的问题,我会将其作为副本关闭。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-13
  • 1970-01-01
  • 1970-01-01
  • 2017-06-24
相关资源
最近更新 更多