// Test. This code crashes even in a playground.
let h = 3, w = 3
// No crash without "📃" symbol!
let fieldStrings: [String] = ["📃", "3", "3", "4", "1", "2", "2", "4", "2"]
let maxLength = fieldStrings.reduce(0) { (maxLength, s) in max(maxLength, s.count) }
print(maxLength) // 1
// No crash without padding!
let paddedFieldStrings = fieldStrings.map { s in
s.padding(toLength: maxLength, withPad: " ", startingAt: 0)
}
var lines = [String]()
for y in 0..<h {
var line = ""
for x in 0..<(w - 1) {
// CRASH HERE! x = 0, y = 0
line += paddedFieldStrings[x * h + y] + " "
}
line += paddedFieldStrings[(w - 1) * h + y]
lines.append(line)
}
U+1F4C3 may be replaced with any other emoji and the code still going to crash.
Crash is always reproduced on iOS13.1.2 device and iOS 13.0 simulator, but there is no crash on iOS 12.2 simulator.
It looks like Swift runtime bug. I don't know where to report it so I send a feedback to Apple and created a question on SO. Someone who have experience with https://bugs.swift.org, please to create an issue.
Update:
Try to run this in playground: print("📃".padding(toLength: 1, withPad: " ", startingAt: 0))
You'll get really large exception, like:
Sorry, playgrounds doesn't allow to copy text of exceptions, so I can only provide the screenshot.
method padding(toLength:withPad:startingAt:) is defined in Foundation, which suggests it's not a String method, but NSString one (also the fact that startingAt is an Int, not String.Index). NSString works with utf-16 code units, where "" has length of 2, not 1. It shouldn't mangle your string anyway, so that's both a bug in your code, and in Foundation
Thanks for filing a radar, more similar issues – more attention to them.
Despite the padding(toLength:withPad:startingAt:) is in Foundation, the call stack on crash shows Swift methods:
|#1|0x00000001d27a4b98 in _swift_stdlib_reportFatalError ()|
|#2|0x00000001d26b65c0 in specialized _fatalErrorMessage(_:_:file:line:flags:) ()|
|#3|0x00000001d26b9bc8 in specialized _copyCollectionToContiguousArray<A>(_:) ()|
|#4|0x00000001d261cbec in _StringGuts._foreignGrow(_:) ()|
|#5|0x00000001d261cff0 in _StringGuts.append(_:) ()|
|#6|0x00000001d26b9fb8 in specialized _StringGuts.append(_:) ()|
|#7|0x0000000100785010 in specialized static String.+ infix(_:_:) [inlined] ()|
|#8|0x0000000100785000 in static String.+ infix(_:_:) [inlined] ()|
|#9|0x0000000100785000 in specialized AppDelegate.application(_:didFinishLaunchingWithOptions:) at ...
So I believe that Foundation is partially implemented on Swift (?).
So, my mistake, talking simple, was to assume that count == length? How can I fix it? I suppose somehow change maxLength calculation, or may be convert everything to NSString.
I think the crash comes from the + operator function that doesn't expect invalid strings passed to it. In my opinion crashing is an okay thing to do when that happens, maybe the error message isn't optimal. (But that's just my opinion, if you think that's a thing that shouldn't happen, I can help you with making an account for bugs.swift.org and creating an issue there)
Yes. I am not sure if bridging between NSString and String can break anything (If there's anyone reading this that knows how objc bridging works, please reassure me) but I think you can change s.count to either s.utf16.count or s.length and it will work