iOS: prettify random color for debugging
I used to use random color to debug, from colors I like
extension CALayer{
func debug(){
let colors = [UIColor.blue, UIColor.magenta, UIColor.red,
UIColor.green, UIColor.brown, UIColor.purple,
UIColor.cyan]
if let color = colors.randomElement().cgColor{
borderColor = color
}
}
}
The effect case:
The colors are not of regularity. Not very pretty.
I want to prettify it. Do some color alignment. The same color for the same UI hierarchy.
achieve something like this.
In order to not make colors repeat, and to show more colors in a page. I use ring buffer.
In order to do some color alignment, the same color for the same UI hierarchy,I use call stack trace. Use the call function as the key for its color.
Here is the code:
// the color ring buffer
struct ColorCluster {
static var shared = ColorCluster()
let colors = [UIColor.blue, UIColor.magenta, UIColor.red,
UIColor.green, UIColor.brown, UIColor.purple,
UIColor.cyan]
var colorRegister = [String: Int]()
var count = -1
mutating func get(_ k: String) -> CGColor{
var index = 0
if let idx = colorRegister[k]{
index = idx
}
else{
count += 1
if count >= colors.count{
count = 0
}
index = count
colorRegister[k] = count
}
return colors[index].cgColor
}
}
extension CALayer{
func debug(){
// call stack trace, remove methods of the system
let libs: Set<String> = ["UIKitCore", "QuartzCore", "CoreFoundation"]
var methods = [String]()
Out: for symbol in Thread.callStackSymbols{
for lib in libs {
if symbol.contains(lib){
break Out
}
}
methods.append(symbol)
}
var edgeColor = UIColor.black.cgColor // color place holder
if let name = methods.last{
edgeColor = ColorCluster.shared.get(name)
}
borderColor = edgeColor
borderWidth = 1
}
}
Usage:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeue(for: PracticeDetailCell.self, ip: indexPath)
cell.layer.debug()
return cell
}
1 Answer 1
I've had a look, and think it should be possible to trim down the ColorCluster-logic quite a bit, mostly by tightening up the get(:
function a bit. Avoiding some if-elsing and only manipulating the index and count once.
struct ColorCluster {
static var shared = ColorCluster()
private init() { }
private let colors: [UIColor] = [.blue, .magenta, .red, .green, .brown, .purple, .cyan]
private var colorRegister = [String: Int]()
private var count = 0
mutating func getColor(for key: String) -> CGColor {
let countIsOutOfBounds = count >= colors.count
let nextAvailableIndex = countIsOutOfBounds ? 0 : count
let index = colorRegister[key] ?? nextAvailableIndex
count = countIsOutOfBounds ? 0 : count + 1
return colors[index].cgColor
}
}
I also had a quick look at the debug-extension. I haven't actually tested it, but the gist is to go down the functional route when creating the array of method-names:
extension CALayer {
func debug() {
// call stack trace, remove methods of the system
let libs: Set<String> = ["UIKitCore", "QuartzCore", "CoreFoundation"]
let methodNames = Thread.callStackSymbols.reduce([String]()) { names, symbol in
let containingSymbol = libs.filter({ symbol.contains(0ドル) })
if containingSymbol.isEmpty {
return names
}
return names + [symbol]
}
var edgeColor = UIColor.black.cgColor // color place holder
if let name = methodNames.last {
edgeColor = ColorCluster.shared.getColor(for: name)
}
borderColor = edgeColor
borderWidth = 1
}
}