我的应用程序有一个提要,它可以包含URL、#hashtag和@推荐的帖子。我用一个叫做ActiveLabel的吊舱来显示它们。这个吊舱做得很好,但是我的饲料在滚动时稍微滞后了。我的提要是一个UICollectionView,而单元格生成稍微滞后一些。当我滚动的时候,我分析了我的应用程序,并分析了滞后的峰值。这种滞后几乎是不明显的,但它使我恼火。

正如您所看到的,主要的违法者是NSRegularExpression搜索。
我试图在没有数据类型实例的情况下,使用.contains(),通过禁用数据检测来稍微优化这一点。这使其速度略有加快,但滞后的峰值依然存在。
let enabledTypes:[ActiveType] = {
var types = [ActiveType]()
if ad.caption.current.string.contains("#") { types.append(.hashtag) }
if ad.caption.current.string.contains("@") { types.append(.mention) }
if ad.caption.current.string.contains("://") { types.append(.url) }
if ad.caption.canExpand { types.append(seeMore) }
return types
}()
label.enabledTypes = enabledTypes我还跟踪了这篇文章中的每一步,这是轻轻松松的,但还不够。所以我得修一下横梁。
ActiveLabel使用的regex语句是
static let hashtagPattern = "(?:^|\\s|$)#[\\p{L}0-9_]*"
static let mentionPattern = "(?:^|\\s|$|[.])@[\\p{L}0-9_]*"
static let urlPattern = "(^|[\\s.:;?\\-\\]<\\(])" + "((https?://|www\\.|pic\\.)[-\\w;/?:@&=+$\\|\\_.!~*\\|'()\\[\\]%#,☺]+[\\w/#](\\(\\))?)" + "(?=$|[\\s',\\|\\(\\).:;?\\-\\[\\]>\\)])"它把它们和
static func getElements(from text: String, with pattern: String, range: NSRange) -> [NSTextCheckingResult]{
guard let elementRegex = try? NSRegularExpression(pattern: pattern, options: [.caseInsensitive]) else { return [] }
return elementRegex.matches(in: text, options: [], range: range)
}搜索其他regexe,以检测hashtag和所提到的内容,但我没有发现任何有意义的地方。
我试图将标签布局到后台线程上,但显然失败了,因为UI不喜欢在后台线程上执行。我可以重写ActiveLabel,主要在后台线程上工作,并且可以使用回调而不是返回类型,但我想避免这种情况。
我在以下方面检测到数据的一些字符串示例:
"Arnie says,Aspen,Str. Small,Varm神jakke,Veldig!Fremst r ubrukt. Kun brukt et,rett og slett har alt for mange jakker #城市#arnie #jakker #ubrukt“ Skjorte pent brukt I “让·保罗·甘塞(Jean Paul genser I) 100%”,“pent brukt✨er Istr.m.”,“男士丝绒里特”,“过客xs-s!”
正如您所看到的,我们的用户主要是hashtag之类的东西,所以其中一个是最重要的。
是否有任何方法可以改进NSRegularExpression 或regex语句以避免性能下降?
发布于 2017-01-17 20:44:05
如@raidfive所示,最有可能的做法是提前创建一个或多个NSRegularExpression实例,并在需要时重用它们。
请注意,由于是regexes的创建/编译对您的时间配置文件产生了最大的影响(至少在您共享的时间概要文件中),缓存regexes可能会为您赢得足够的性能,您不再需要只启用所需的检测元素的中间优化。在这种情况下,您只需要一个regex (表示所有可能的元素类型的检测),所以缓存/重用很容易。
此外,请注意,您的中间“优化”可能实际上并没有提高性能--它甚至可能会损害性能。匹配正则表达式,无论多么复杂,都需要搜索整个字符串(粗略地)一次。试图确定要检测哪些元素类型意味着要多次搜索字符串--每次contains("#") (etc)测试一次,然后再一次根据正则表达式计算字符串。重复的字符串搜索可能比编译单个正则表达式花费更多。
如果在实现了单个缓存的通用正则表达式之后,仍然(不知怎么地)限制了regex性能,那么您可以缓存多个正则表达式,每个搜索场景都缓存一个正则表达式。组合计算的结果可能是这样的,与需要处理的字符串相比,仍然有更少的不同正则表达式,因此,如果在用户开始滚动之前编译它们,那么在滚动期间编译它们的时间成本就不高了。但是,根据上一段,只有当您有一种廉价的(即不是字符串搜索)方法来检测每个字符串需要哪个正则表达式时,这才有意义。
发布于 2017-01-17 19:56:45
您可以尝试在变量(类或实例)中创建和存储NSRegularExpression实例,因此您只需要创建它们一次。
https://stackoverflow.com/questions/41705728
复制相似问题