编译器选择错误的初始化程序

时间:2017-04-05 22:19:04

标签: swift xcode

我有一个com.springsource.org.aopalliance-1.0.0.jar错误,一直出现,我需要一些帮助。我相信我已经设法确定了错误指针的来源,但我对如何修复它感到茫然。

显然swift编译器为我的一个类选择了错误的初始化程序。根据Instruments,有时当初始化类EXC_BAD_ACCESS(code=2 ...)时,它会调用Description的初始值设定项。不是所有的时间,有时候。无论编译器是设置为-Onone还是-O整个模块优化,它都会执行此操作。

这是两个类的样子:

LyricBlock

如您所见,class LyricBlock: Node, LeftDelimited, RightDelimited { var leftDelimiter: Delimiter var rigthDelimiter: Delimiter init(start: Int, body: Range<Int>, end: Int) { self.leftDelimiter = Delimiter(range: start..<body.lowerBound) self.rightDelimiter = Delimiter(range: body.upperBound..<end) super.init(range: body) } } class Description: Node, LeftDelimited, RightDelimited { var leftDelimiter: Delimiter var leftDelimiter: Delimiter init(start: Int, body: Range<Int>, end: Int) { self.leftDelimiter = Delimiter(range: start..<body.lowerBound) self.rightDelimiter = Delimiter(range: body.upperBound..<end) super.init(range: body) } } LyricBlock继承自Description基类并共享一些协议,但除此之外它们彼此无关。

一些可能相关的代码:

Node

作为旁注,我想知道我是否可能遇到类签名的错误问题,并尝试使用class Node { weak var parent: Node? var next: Node? var firstChild: Node? weak var lastChild: Node? let offset: Int internal(set) var length: Int init(range: Range<Int>) { self.offset = range.lowerBound self.length = range.upperBound - range.lowerBound } func addChild(_ child: Node) { if firstChild == nil { firstChild = child } else { lastChild?.next = child } lastChild = child child.parent = self } } class Parser { // ... func processLine(in buffer: Buffer) { // Parse the current line as a block node. var block = blockForLine(in: buffer) // Try to find an appropriate container node. If none can be found, block will be replaced with Description. let container = appropriateContainer(for: &block, in: buffer) container.addChild(block) // Edge case to parse first-line lyrics if let cueBlock = block as? CueBlock { if let lyricBlock = scanForLyric(in: buffer, at: cueBlock.direction.range.lowerBound) { let lyricContainer = LyricContainer(range: lyricBlock.range.lowerBound..<endOfLineCharNumber) lyricContainer.addChild(lyricBlock) cueBlock.replaceDirection(with: lyricContainer) parseInlines(for: lyricBlock, in: buffer) } } // Parse inlines as appropriate switch block { case is FacsimileBlock, is Description, is LyricBlock: parseInlines(for: block, in: buffer) // ... } } func blockForLine(in buffer: Buffer) -> Node { let whitespace = buffer.scanForFirstNonspace(at: charNumber, limit: endOfLineCharNumber) // ... let endWhitespace = buffer.scanBackwardForFirstNonspace(at: endOfLineCharNumber, limit: wc) let description = Description(start: charNumber, body: whitespace..< endWhitespace, end: endOfLineCharNumber) return description } func appropriateContainer(for block: inout Node, in buffer: Buffer) -> Node { switch block { // These block types can only ever be level-1 case is Header, is Description, is EndBlock, is HorizontalBreak: return root // ... case is LyricBlock: guard let cueContainer = root.lastChild as? CueContainer else { break } guard let cueBlock = cueContainer.lastChild as? CueBlock else { break } guard let direction = cueBlock.direction as? LyricContainer else { break } direction.extendLengthToInclude(node: block) cueBlock.extendLengthToInclude(node: direction) cueContainer.extendLengthToInclude(node: cueBlock) return direction default: break } let whitespace = buffer.scanForFirstNonspace(at: charNumber, limit: endOfLineCharNumber) let endWhitespace = buffer.scanBackwardForFirstNonspace(at: endOfLineCharNumber, limit: wc) // Invalid syntax, time to fail gracefully block = Description(start: charNumber, body: whitespace..< endWhitespace, end: endOfLineCharNumber) return root } func parseInlines(for stream: Node, in buffer: Buffer) { // ... scans buffer for inlines and enques them in queue while let next = queue.dequeue() { let nextRange = next.rangeIncludingMarkers if nextRange.lowerBound > j { let lit = Literal(range: j..<nextRange.lowerBound) stream.addChild(lit) } stream.addChild(next) j = nextRange.upperBound } if j < endOfLineCharNumber { let lit = Literal(range: j..<nodeRange.upperBound) stream.addChild(lit) } } // ... } 的{​​{1}}和rightDelimiter属性而不是使用协议。这导致编译器调用我的leftDelimiter初始值设定项。我不知道这证明了什么。坦率地说,我很茫然。帮助

1 个答案:

答案 0 :(得分:0)

经过一些修修补补后,我能够至少部分解决这个问题。

事实证明,无论出于何种原因,ARC都会在超过一定规模的链接列表上疯狂。我能够通过在新项目中创建一个通用链表来确认这一点,然后慢慢地用更长的列表来测试它。

class LLNode<T> {

    var value: T?

    var next: LLNode<T>?

    weak var previous: LLNode<T>?

}

class LList<T> {

    var head: LLNode<T>

    var tail: LLNode<T>

    // boring old linked list implementation

}

let list = List<Int>()
for i in 0..<10000 {
    list.append(i)
}

果然,在大约10,000个节点之后,我开始在通用列表上再次获得EXC_BAD_ACCESS,但仅在list被取消初始化时。这与我上面的解析器完全匹配的行为相匹配。由于我的代码使用链接列表来模拟树中的子项(引用计数的两个维度!),因此ARC必须自己解决所有这些引用 - 并且失败。为什么它会像那样崩溃仍然超出我的解释能力,但这至少解释了崩溃的

为了确认,我在C中创建了另一个链表,并在其周围创建了一个Swift包装器,所有垃圾收集都在C中实现。

import liblist

class List<T> {

    var list: UnsafeMutablePointer<llist>

    // Swift interface with list

    deinit {
        list_free(list)
    }
}

包装器能够处理我投掷的每个尺寸 - 多达500,000个节点,此时我感到满意并停止测试。

如果有人对我用来解决这个问题的完整代码感兴趣,我在https://github.com/dmcarth/List创建了一个Swift包