Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift 2.1 Error sorting in place, only on release builds

I started getting crash reports for the sort lamdba in the below code, the third line in the grey box below:

private func fixOverlaps(inout blocks: [TimeBlock], maxOverlaps: Int? = nil) {
    blocks.sortInPlace { a,b in
        if a.startTime < b.startTime {
            return true
        } else if a.startTime == b.startTime && a.endTime < b.endTime {
            return true
        }
        return false
    }
...

Note the crash does not occur on debug builds from XCode. Only the App Store and Ad Hoc archives will crash, and only when the length of the blocks list is in the hundreds.

I modified the code to this, and the problem went away:

private func fixOverlaps(inout blocks: [TimeBlock], maxOverlaps: Int? = nil) {
    blocks = blocks.sort { a,b in
        if a.startTime < b.startTime {
            return true
        } else if a.startTime == b.startTime && a.endTime < b.endTime {
            return true
        }
        return false
    }
...

Is there something I've missed about how to use inout or sortInPlace? I can try to do a demo of this. It's on multiple versions of iOS (8/9) and Swift 2.1.

EDIT--------------------

Ok here's a minimal version that crashes. Turns out the inout was a red herring. If you start a new single view project in XCode 7.1, you can replace the view controller with this:

class ViewController: UIViewController {

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    var blocks = [TimeBlock]()
    for var i in 0...20 { //Works if you put in a small number like 8
        let t = TimeBlock()
        t.start = Int(arc4random_uniform(1000)) //Get some random numbers so the sort has to do some work
        t.end = Int(arc4random_uniform(1000))
        blocks.append(t)
    }

    blocks.sortInPlace { a,b in
        if a.start > b.start {
            return true
        }
        return false
    }

    print("done") //Gets here on debug, not release
}

class TimeBlock {
    var start = 0
    var end = 0
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}


}

So run it in release, and you should see it prints "Done" if you end the loop at around 17 but crashes with 20. Exact number might be different for you.

like image 653
Carlos Avatar asked Oct 30 '15 20:10

Carlos


1 Answers

Worked around this without loss of functionality by using self.list = self.list.sort() instead of self.list.sortInPlace().

like image 198
Dennis L Avatar answered Nov 15 '22 13:11

Dennis L