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

Posted

技术标签:

【中文标题】如何循环遍历动态大小的数组并将属性作为参数传递给可变参数函数?【英文标题】:How to loop through array of dynamic size and pass properties as arguments in variadic function? 【发布时间】:2019-04-23 01:19:35 【问题描述】:

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

我正在为 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 类型具有与之关联的 photoUrl。

由于引脚类型的数量将来可能会发生变化,我必须在我的应用程序中提取类型,将它们解析为一组自定义对象,然后循环遍历每个对象并将它们的信息添加到 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 += "%@)"

我们的“格式”字符串的最终结果将始终如下所示(尽管具有不同数量的 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)

第一个参数是格式字符串,所有其他参数都是“填充”该格式字符串的NSExpressions。如何在 pinTypes 数组中“循环”并为每个数组创建一个单独的 NSExpression,并在设置样式层的 iconImageProperty 时将每个单独的 NSExpression 作为参数传递?

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

【问题讨论】:

【参考方案1】:

我可能误解了这个问题。我不知道你是否想要一个通用的方法来做到这一点,但NSExpression 有一个带有数组的 init: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)

希望这会有所帮助。我坐在我的桌面上,所以我自己无法真正测试任何东西。

【讨论】:

非常感谢,我以前从未使用过 NSExpressions,但了解它们是 NSPredicate 的对应物。我在想我可以将数组作为参数传递,但还没有研究 NSExpression 是否有一个用于获取数组的 init。 Mapbox 示例的 init 采用格式字符串和可变参数。让我试试这个并回复你! 这实际上工作得很好。我不得不稍微编辑 NSExpressions,因为我对它们如何工作的理解有点偏离,但只要 NSExpressions 的数组是正确的,将数组作为参数传递就很好。

以上是关于如何循环遍历动态大小的数组并将属性作为参数传递给可变参数函数?的主要内容,如果未能解决你的问题,请参考以下文章

如何将相同的事件侦听器分配给 Vue.js 中动态创建的按钮并将对象的值作为参数传递给它?

将固定大小的特征矩阵作为参数传递给调用动态大小矩阵的函数

将对象作为参数传递给构造函数并将其属性复制到新对象?

如何将对象属性作为参数传递给 Razor 组件

声明一个带有数组参数的python函数并将一个数组参数传递给函数调用?

如何将具有多个对象的状态数组作为参数传递给graphql突变?