如何遍历动态大小的数组并将属性作为参数传递给可变参数函数?

How to loop through array of dynamic size and pass properties as arguments in variadic function?

我有一个有趣的问题,我不确定我想做的事情是否可行。如果没有,我想我的问题还有其他解决方法。

我正在为 iOS 使用 Mapbox(MapKit 替代品)。 Mapbox 具有样式层,可让您为地图上的不同图钉设置不同的图像。这是通过将图层的 iconImageName 设置为不同的值来完成的,具体取决于它正在处理的地图图钉。作为样式层的 iconImageName 给出的值是一个 NSExpression,我们在其中将格式作为字符串和任何其他数量的 NSExpression 传递,以便它们符合格式。下面是从 动态图像创建样式层的示例,即这些图像被硬编码到应用程序中。

//Create the layer
let ports = MGLSymbolStyleLayer(identifier: "ports", source: source)
//Create a default shape
let defaultShape = NSExpression(forConstantValue: "grayMarker")

//For every pin in the 'ports' layer, we are going to look at its 
//'type' property. If 'type' is equal to the string 'redPin', its image 
//should be the one registered with the name 'redMarker'. If 'type' is 
//equal to the string 'bluePin', its image should be the one registered 
//with the name 'blueMarker'...and so on. If 'type' doesn't match 
//anything outlined here, then set the pin's image to the default 
//shape.
ports.iconImageName = NSExpression(format: "MGL_MATCH(type, 'redPin', %@, 'bluePin', %@, 'greenPin', %@, 'grayPin', %@, %@)", NSExpression(forConstantValue: "redMarker"), NSExpression(forConstantValue: "blueMarker"), NSExpression(forConstantValue: "greenMarker"), NSExpression(forConstantValue: "grayMarker"), defaultShape)

//Add the layer to the map's style
self.mapStyle!.addLayer(ports)

因此,当信息被硬编码到应用程序中时,这很容易做到。问题是,我有一系列从 API 请求返回的 "pin types",我可能需要在以后进行更改。这些 pin 类型有一个与之关联的 photoUrl。

由于未来 pin 类型的数量可能会发生变化,我必须在我的应用程序中提取类型,将它们解析为一组自定义对象,然后遍历每个对象并将它们的信息添加到 NSExpression 的格式。下面是我如何做的一个例子:

//Create a new style layer, like in the previous example
let icons = MGLSymbolStyleLayer(identifier: "icons", source: source)

//Create a prefix type string for our format string. We will modify 
//this based on the data in our categories 
var format = "MGL_MATCH(type, "

//Loop through the array and modify our format string to include our 
//pin type
for pinType in self.pinTypes {
    format += "'\(pinType.id ?? "")', %@, "
}

//Add the suffix to the format string
format += "%@)"

我们的 'format' 字符串的最终结果将始终如下所示(尽管有不同数量的 pinType):

MGL_MATCH(type, '0lah2lqnit8sae8', %@, 'moyxexbimf988g3', %@, 'rweisxrjjahriou', %@, 'phn9kssirq6p99f', %@, 'wgpyy6bvw0dxmfp', %@, 'knj2q61ip0xfspy', %@, 'q8e5zqkm8aj9bvl', %@, '16rxmcilhes742c', %@, 'c2srv0rkx3wtagm', %@, 'jorbix53907eikq', %@, 'L1E5cRH2mVWC5qp', %@, 'Aur0Ok57zrtxBiL', %@, 'i5261q9qjqaftfh', %@, '9ru1hhcjwqx4c51', %@, 'ebnxme3pwq6q7o3', %@, 'oyn45ntbub7upei', %@, 'hb1fy24bme5e040', %@, 'xr2pmgtged1w678', %@, '97st6t0fwb6anwz', %@, 'ovwe99ejboz7zpb', %@, 'amvm4xe85s0g6sx', %@, 'gj801lf4co3h1zm', %@, '7emo3defagedy6l', %@, '9atby0ig427fkc4', %@, '6w4asp3yxs4e6ez', %@, 'tdmmyqwtn5ncy55', %@, 'yd4epiob1mg6tc3', %@, 'icb59kmni3thlmd', %@, 'eh9mgf4lp50ar88', %@, 'lxjccng4fb7sk05', %@, '2jg3aqkltbsktof', %@, 'e0otypxpbq2syzm', %@, '25af3o1wxo77s8b', %@, '1r6z9zdi8uxtf7m', %@, 't1zxv955vw5dfep', %@, 'iq93veeuccsrqye', %@, 'osviabneknsqo2x', %@, 'u6mps2zv2ivs4n8', %@, 'r2q9u8dhhk94km4', %@, 'wp6jmyyeh17nocd', %@, '4now4xnrylx7010', %@, 'f8uy2twfr2r3m7f', %@, 'lhw9bs31nr2twlx', %@, 'qvnfna00n9wnkgu', %@, 'g8f5zc7gcei1aax', %@, 'spxlscffbf0ve9q', %@, 'dir96qh9w1n43ys', %@, 'dgrj9voh1ybhv5j', %@, 'hdwp8w1lfhcurq9', %@, 'twpx9aeb5kkkju2', %@, 'eb85y3w2zywfpet', %@, '9dd6yp6c3e4oyno', %@, 'd61qrfm60vq4mqh', %@, 'hcjxvgzr0kiqbsf', %@, 'izygh92tmdd5r07', %@, 'ymd2p3k5voo27te', %@, 'l87mls4z0zy534u', %@, 'ybr1twmjafdr1cf', %@, 'eqeio0phb1gj50y', %@, 'dn48bxo5hkt7295', %@, 'uE5z1pDR6U1pPhR', %@, '6801ek42qsn1hl2', %@, 'BWPcCGJ0bTlqYhj', %@, 'wzEaDVI28xvuENW', %@, 'yiXttIPk0oLQAc3', %@, 'b6nadw9emiband2', %@, 'yxt8w275plqxws4', %@, '99lo09p6wr8wcdv', %@, '1hhoeiony8jt0rx', %@, 'bkcmo89dcvdh7px', %@, 'nz8d748p4np9bll', %@, '6vpts6ytusz51n5', %@, %@)

因此,我能够获取使用从我们的 API 请求中提取的动态数据创建的格式字符串,但现在是困难的部分。如何将动态数量的参数传递给函数?!

请注意,下一步是将 iconImageName 属性 设置为可以接受任意数量参数的 NSExpression。回忆一下我们的第一个硬编码数据示例:

ports.iconImageName = NSExpression(format: "MGL_MATCH(type, 'redPin', %@, 'bluePin', %@, 'greenPin', %@, 'grayPin', %@, %@)", NSExpression(forConstantValue: "redMarker"), NSExpression(forConstantValue: "blueMarker"), NSExpression(forConstantValue: "greenMarker"), NSExpression(forConstantValue: "grayMarker"), defaultShape)

第一个参数是格式字符串,所有其他参数都是 NSExpression,即 'populating' 格式字符串。我如何 'loop' 通过 pinTypes 数组并为每个创建一个单独的 NSExpression 并在设置样式层的 iconImageProperty 时将每个单独的 NSExpression 作为参数传递?

TLDR 有没有一种方法可以在将参数传递给可以接受任意数量参数的函数时循环遍历一个大小可能不同的数组,从该数组中的每个元素创建一个对象,然后将它作为参数传递给函数可以接受任意数量的参数?

我可能误解了这个问题。我不知道你是否想要一个通用的方法来做到这一点,但是 NSExpression 有一个接受数组的初始化:https://developer.apple.com/documentation/foundation/nsexpression/1413484-init

所以你可以这样做:

let defaultShapeExpression = NSExpression(forConstantValue: "grayMarker")
// Either do clean array or add your initial arguments
var expressionArguments = [Any]()
var format = "MGL_MATCH(type, "

for pinType in self.pinTypes {
    format += "'\(pinType.id ?? "")', %@, "
    expressionArguments.append(NSExpression(pinType.iconImageProperty))
}

format += "%@)"
expressionArguments.append(defaultShapeExpression)

let expression = NSExpression(format: format, argumentArray: expressionArguments)

希望这对您有所帮助。我坐在我的桌面上,所以我不能自己测试任何东西。