使用MGL_MATCH表达式设置Mapbox图层填充色时崩溃的问题求助
嘿,我看你遇到的问题很典型——直接把UIColor对象拼进表达式字符串里,Mapbox根本没法正确解析它!咱们一步步来解决:
问题根源
你代码里的核心错误是:在构建MGL_MATCH表达式时,把UIColor实例直接通过appendFormat拼到了字符串里。这样生成的表达式里会出现类似<UIColor: 0x600003a7c060>这样的字符串,Mapbox试图把这个字符串当成颜色值处理时,就会调用mgl_color方法,而NSString根本没有这个方法,直接触发崩溃。
另外还有个逻辑问题:你提前遍历所有features来构建MATCH表达式的做法并不合适——矢量瓦片是按需加载的,你一开始获取的features只是当前视口内的,后续滑动地图加载新瓦片时,那些新的features不会被你的表达式覆盖到。
修复方案(推荐):用表达式直接判断前缀
既然你的需求是匹配以"06"开头的jpt_kod_je值,完全不用遍历所有features,直接用Mapbox的表达式函数来实现,简洁又高效:
func mapViewDidFinishLoadingMap(_ mapView: MGLMapView) { guard let layer = mapView.style?.layer(withIdentifier: "powiaty-1") as? MGLFillStyleLayer else { return } // 构建表达式:判断jpt_kod_je的前缀是否为"06",是则红色,否则白色 let fillColorExpression = NSExpression( format: """ MGL_CONTAINS(MGL_PREFIX(jpt_kod_je, 2), "06") ? \(MGLColorValue(UIColor.red).expression) : \(MGLColorValue(UIColor.white).expression) """ ) layer.fillColor = fillColorExpression }
或者用MGL_MATCH结合MGL_PREFIX来实现,逻辑更清晰:
let fillColorExpression = NSExpression( format: """ MGL_MATCH( MGL_PREFIX(jpt_kod_je, 2), "06", \(MGLColorValue(UIColor.red).expression), \(MGLColorValue(UIColor.white).expression) ) """ )
如果你确实需要匹配具体的code值(不推荐这种遍历方式,但可以修复)
如果一定要遍历feature的code来构建MATCH表达式,那你需要把UIColor转换成Mapbox表达式能识别的格式——可以用MGLColorValue的expression属性,或者用MGL_COLOR(r, g, b, a)的格式:
func mapViewDidFinishLoadingMap(_ mapView: MGLMapView) { guard let layer = mapView.style?.layer(withIdentifier: "powiaty-1") as? MGLFillStyleLayer, let source = mapView.style?.source(withIdentifier: "composite") as? MGLVectorTileSource else { return } let features = source.features(sourceLayerIdentifiers: ["powiaty"], predicate: nil) ?? [] var matchClauses: [String] = [] for feature in features { guard let code = feature.attribute(forKey: "jpt_kod_je") as? String else { continue } let color = code.prefix(2) == "06" ? UIColor.red : UIColor.white // 把UIColor转换成表达式能用的格式 let colorExpr = MGLColorValue(color).expression matchClauses.append("\"\(code)\", \(colorExpr)") } // 拼接完整的MATCH表达式 let matchExprString = "MGL_MATCH(jpt_kod_je, \(matchClauses.joined(separator: ", ")), \(MGLColorValue(UIColor.white).expression))" layer.fillColor = NSExpression(format: matchExprString) }
但还是要强调:这种方式只对当前已加载的features有效,后续加载的新瓦片里的feature不会被匹配到,所以优先用前面的前缀判断方案。
验证你的表达式
建议在设置表达式前先打印出来,确保格式正确。比如正确的表达式应该是:
MGL_MATCH(MGL_PREFIX(jpt_kod_je, 2), "06", MGL_COLOR(1,0,0,1), MGL_COLOR(1,1,1,1))
而不是包含<UIColor>字符串的错误格式。
内容的提问来源于stack exchange,提问作者Krzysiek Szymański

