我的应用程序有一个feed,其中的帖子可以包含URL、#标签和@提及。我用一个叫做ActiveLabel的吊舱来显示它们。这个豆荚做得很好,但我的饲料稍微滞后滚动。我的饲料是一个UICollectionView,细胞生成稍微滞后。我在滚动时分析了我的应用程序,并分析了滞后峰值。这个滞后几乎是看不见的,但它使我恼火。
ios - 优化NSRegularExpression性能-LMLPHP
如您所见,主要的犯罪者是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

我也遵循了this article中的每一步,这有点帮助,但还不够。所以我需要修好正则表达式。
regex语句ActiveLabel使用的是
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)
}

搜索其他regex以检测标签和提及,但我没有找到任何有区别的东西。
我试着在后台线程上布局标签,但很明显,这失败了,因为UI不喜欢在后台线程上完成。我可以重写ActiveLabel,使其主要在后台线程上工作,在后台线程上可以使用回调而不是返回类型,但我想避免这样做。
我检测数据的字符串示例:
“阿尼说,阿斯彭。小街。上帝啊,雅克。维迪格鳍!弗雷姆斯特乌布鲁克。Kun brukt et par ganger,为mange jakker🙈urbanţarnieţsaysţaspenţubrukt更新slett fordi jeg har alt”
“Skjort pent brukt i Organik bomull fra tom tailor originalpris 300 KROrganikBomullsjortbomullflower”花
“Jean Paul genser i 100%ull,pent brukt✨er i str.m,men veldig liten,passer xs-s!\n#jeanpaul#genserාclassyාlitebrukt񖓿brunාull“
如你所见,我们的用户主要是标签的东西,所以其中一个是最重要的。
有什么方法可以改进NSRegularExpression或regex语句以避免性能下降吗?

最佳答案

As @raidfive suggests,最有可能的做法是提前创建一个或多个NSRegularExpression实例,并在需要时重用它们。
请注意,由于regex的创建/编译对您的时间配置文件的影响最大(至少,在您共享的时间配置文件中影响最大),缓存regex可能会为您赢得足够的性能,使您不再需要进行中间优化,只启用所需的检测元素。在这种情况下,只需要一个regex(表示所有可能的元素类型的检测),因此缓存/重用很容易。
此外,请注意,中间的“优化”可能实际上并不能从一开始就提高性能—它甚至可能损害性能。匹配正则表达式,无论多么复杂,都需要搜索整个字符串(大致)一次。尝试确定要检测的元素类型意味着多次搜索字符串-每次搜索一个contains("#")(etc)测试,然后再次根据正则表达式计算字符串。重复的字符串搜索可能要比编译一个正则表达式花费更多。
如果在实现了单个缓存的通用regex之后发现(不知何故)在regex性能上仍然处于劣势,那么可以缓存多个regex,每个搜索场景处理一个regex。组合数学的工作原理可能是,与要处理的字符串相比,您仍然拥有更少的不同正则表达式,因此,如果您在用户开始滚动之前编译所有正则表达式,那么您就不会在滚动期间支付编译它们的时间成本。不过,在前一段中,只有当您有一种廉价的(即不是字符串搜索)方法来检测每个字符串所需的正则表达式时,这才有意义。

关于ios - 优化NSRegularExpression性能,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/41705728/

10-09 22:44
查看更多