gpt4 book ai didi

ios - SwiftyJSON 性能问题

转载 作者:IT王子 更新时间:2023-10-29 05:19:02 27 4
gpt4 key购买 nike

在从我们的 API 使用 SwiftyJson 解析 JSON 并填充核心数据时,我遇到了严重的性能问题。

数据是使用 Alamofire 下载的,它运行良好,但使用 SwiftyJson 解析 JSON 非常慢。为了查看库是否真的是问题所在,我在解析数据的众多地方之一重写了 json 解析。在下面的代码中,我正在解析大约 400 个旅游景点之一的开放时间。

查看这些屏幕截图中的差异,7.7 秒到 185 毫秒:

enter image description here

enter image description here

Swifty 方式:

    let openDescription:String = json["OpeningHours"]["OpeningHoursGenericExceptions"].string!
let monOpen:[String] = json["OpeningHours"]["Monday"]["From"].string!.componentsSeparatedByString(":")
let monClose:[String] = json["OpeningHours"]["Monday"]["To"].string!.componentsSeparatedByString(":")
let tueOpen:[String] = json["OpeningHours"]["Tuesday"]["From"].string!.componentsSeparatedByString(":")
let tueClose:[String] = json["OpeningHours"]["Tuesday"]["To"].string!.componentsSeparatedByString(":")
let wedOpen:[String] = json["OpeningHours"]["Wednesday"]["From"].string!.componentsSeparatedByString(":")
let wedClose:[String] = json["OpeningHours"]["Wednesday"]["To"].string!.componentsSeparatedByString(":")
let thuOpen:[String] = json["OpeningHours"]["Thursday"]["From"].string!.componentsSeparatedByString(":")
let thuClose:[String] = json["OpeningHours"]["Thursday"]["To"].string!.componentsSeparatedByString(":")
let friOpen:[String] = json["OpeningHours"]["Friday"]["From"].string!.componentsSeparatedByString(":")
let friClose:[String] = json["OpeningHours"]["Friday"]["To"].string!.componentsSeparatedByString(":")
let satOpen:[String] = json["OpeningHours"]["Saturday"]["From"].string!.componentsSeparatedByString(":")
let satClose:[String] = json["OpeningHours"]["Saturday"]["To"].string!.componentsSeparatedByString(":")
let sunOpen:[String] = json["OpeningHours"]["Sunday"]["From"].string!.componentsSeparatedByString(":")
let sunClose:[String] = json["OpeningHours"]["Sunday"]["To"].string!.componentsSeparatedByString(":")

原生方式:

    var monOpen:[String] = []
var monClose:[String] = []
var tueOpen:[String] = []
var tueClose:[String] = []
var wedOpen:[String] = []
var wedClose:[String] = []
var thuOpen:[String] = []
var thuClose:[String] = []
var friOpen:[String] = []
var friClose:[String] = []
var satOpen:[String] = []
var satClose:[String] = []
var sunOpen:[String] = []
var sunClose:[String] = []
var openDescription:String = ""

if let attractionsArray = orgJson as? NSArray{
if let attraction = attractionsArray[0] as? NSDictionary{
if let openHours = attraction["OpeningHours"] as? NSDictionary{
if let day = openHours["Monday"] as? NSDictionary{
if let open = day["From"] as? String{
monOpen = open.componentsSeparatedByString(":")
}
if let close = day["To"] as? String{
monClose = close.componentsSeparatedByString(":")
}
}
if let day = openHours["Tuesday"] as? NSDictionary{
if let open = day["From"] as? String{
tueOpen = open.componentsSeparatedByString(":")
}
if let close = day["To"] as? String{
tueClose = close.componentsSeparatedByString(":")
}
}
if let day = openHours["Wednesday"] as? NSDictionary{
if let open = day["From"] as? String{
wedOpen = open.componentsSeparatedByString(":")
}
if let close = day["To"] as? String{
wedClose = close.componentsSeparatedByString(":")
}
}
if let day = openHours["Thursday"] as? NSDictionary{
if let open = day["From"] as? String{
thuOpen = open.componentsSeparatedByString(":")
}
if let close = day["To"] as? String{
thuClose = close.componentsSeparatedByString(":")
}
}
if let day = openHours["Friday"] as? NSDictionary{
if let open = day["From"] as? String{
friOpen = open.componentsSeparatedByString(":")
}
if let close = day["To"] as? String{
friClose = close.componentsSeparatedByString(":")
}
}
if let day = openHours["Saturday"] as? NSDictionary{
if let open = day["From"] as? String{
satOpen = open.componentsSeparatedByString(":")
}
if let close = day["To"] as? String{
satClose = close.componentsSeparatedByString(":")
}
}
if let day = openHours["Sunday"] as? NSDictionary{
if let open = day["From"] as? String{
sunOpen = open.componentsSeparatedByString(":")
}
if let close = day["To"] as? String{
sunClose = close.componentsSeparatedByString(":")
}
}
if let desc = openHours["OpeningHoursGenericExceptions"] as? String{
openDescription = desc
}
}
}
}

这只是被解析数据的一部分,因此应用中的性能非常明显。

我想问题是,我是否错误地使用了 SwiftyJSON 还是这是预料之中的?

最佳答案

首先,你的“native way”不等同于“Swifty way”。

SwiftyJSON版本有45个subscript访问,而原生方式只有23个subscript访问。

要使“本地方式”等效,它应该是这样的:

let openDescription = attraction["OpeningHours"]!["OpeningHoursGenericExceptions"] as String
let monOpen = (attraction["OpeningHours"]!["Monday"]!!["From"] as String).componentsSeparatedByString(":")
let monClose = (attraction["OpeningHours"]!["Monday"]!!["To"] as String).componentsSeparatedByString(":")
let tueOpen = (attraction["OpeningHours"]!["Tuesday"]!!["From"] as String).componentsSeparatedByString(":")
let tueClose = (attraction["OpeningHours"]!["Tuesday"]!!["To"]! as String).componentsSeparatedByString(":")
// ...

或“Swifty way”应该是这样的:

let openHours = json[0]["OpeningHours"]
var day:JSON

day = openHours["Monday"]
if let open = day["From"].string {
monOpen = open.componentsSeparatedByString(":")
}
if let close = day["To"].string {
monClose = close.componentsSeparatedByString(":")
}
day = openHours["Tuesday"]
if let open = day["From"].string {
tueOpen = open.componentsSeparatedByString(":")
}
if let close = day["To"].string {
tueClose = close.componentsSeparatedByString(":")
}
// ...

无论如何,是的,SwiftyJSON 很慢。让我们测量一下:

import Foundation
import XCTest

let orgJson:AnyObject = [
[
"OpeningHours": [
"OpeningHoursGenericExceptions": "test",
"Monday": ["From":"1:2:3","To":"1:2:3"],
"Tuesday": ["From":"1:2:3","To":"1:2:3"],
"Wednesday": ["From":"1:2:3","To":"1:2:3"],
"Thursday": ["From":"1:2:3","To":"1:2:3"],
"Friday": ["From":"1:2:3","To":"1:2:3"],
"Saturday": ["From":"1:2:3","To":"1:2:3"],
"Sunday": ["From":"1:2:3","To":"1:2:3"],
]
]
]
let json = JSON(orgJson)

class JSONTestTests: XCTestCase {

func testNativeSubscript() {
measureBlock { () -> Void in

for _ in 0 ..< 400 {
autoreleasepool {
if let attraction = orgJson[0] as? NSDictionary {
let openDescription = attraction["OpeningHours"]!["OpeningHoursGenericExceptions"] as String
let monOpen = (attraction["OpeningHours"]!["Monday"]!!["From"] as String).componentsSeparatedByString(":")
let monClose = (attraction["OpeningHours"]!["Monday"]!!["To"] as String).componentsSeparatedByString(":")
let tueOpen = (attraction["OpeningHours"]!["Tuesday"]!!["From"] as String).componentsSeparatedByString(":")
let tueClose = (attraction["OpeningHours"]!["Tuesday"]!!["To"] as String).componentsSeparatedByString(":")
let wedOpen = (attraction["OpeningHours"]!["Wednesday"]!!["From"] as String).componentsSeparatedByString(":")
let wedClose = (attraction["OpeningHours"]!["Wednesday"]!!["To"] as String).componentsSeparatedByString(":")
let thuOpen = (attraction["OpeningHours"]!["Thursday"]!!["From"] as String).componentsSeparatedByString(":")
let thuClose = (attraction["OpeningHours"]!["Thursday"]!!["To"] as String).componentsSeparatedByString(":")
let friOpen = (attraction["OpeningHours"]!["Friday"]!!["From"] as String).componentsSeparatedByString(":")
let friClose = (attraction["OpeningHours"]!["Friday"]!!["To"] as String).componentsSeparatedByString(":")
let satOpen = (attraction["OpeningHours"]!["Saturday"]!!["From"] as String).componentsSeparatedByString(":")
let satClose = (attraction["OpeningHours"]!["Saturday"]!!["To"] as String).componentsSeparatedByString(":")
let sunOpen = (attraction["OpeningHours"]!["Sunday"]!!["From"] as String).componentsSeparatedByString(":")
let sunClose = (attraction["OpeningHours"]!["Sunday"]!!["To"] as String).componentsSeparatedByString(":")
XCTAssertEqual(monOpen, ["1","2","3"], "")
XCTAssertEqual(openDescription, "test")
}
}
}
}
}

func testJSONSubscript() {
measureBlock { () -> Void in
for _ in 0 ..< 400 {
autoreleasepool {
let attraction = json[0]
let openDescription:String = attraction["OpeningHours"]["OpeningHoursGenericExceptions"].string!
let monOpen:[String] = attraction["OpeningHours"]["Monday"]["From"].string!.componentsSeparatedByString(":")
let monClose:[String] = attraction["OpeningHours"]["Monday"]["To"].string!.componentsSeparatedByString(":")
let tueOpen:[String] = attraction["OpeningHours"]["Tuesday"]["From"].string!.componentsSeparatedByString(":")
let tueClose:[String] = attraction["OpeningHours"]["Tuesday"]["To"].string!.componentsSeparatedByString(":")
let wedOpen:[String] = attraction["OpeningHours"]["Wednesday"]["From"].string!.componentsSeparatedByString(":")
let wedClose:[String] = attraction["OpeningHours"]["Wednesday"]["To"].string!.componentsSeparatedByString(":")
let thuOpen:[String] = attraction["OpeningHours"]["Thursday"]["From"].string!.componentsSeparatedByString(":")
let thuClose:[String] = attraction["OpeningHours"]["Thursday"]["To"].string!.componentsSeparatedByString(":")
let friOpen:[String] = attraction["OpeningHours"]["Friday"]["From"].string!.componentsSeparatedByString(":")
let friClose:[String] = attraction["OpeningHours"]["Friday"]["To"].string!.componentsSeparatedByString(":")
let satOpen:[String] = attraction["OpeningHours"]["Saturday"]["From"].string!.componentsSeparatedByString(":")
let satClose:[String] = attraction["OpeningHours"]["Saturday"]["To"].string!.componentsSeparatedByString(":")
let sunOpen:[String] = attraction["OpeningHours"]["Sunday"]["From"].string!.componentsSeparatedByString(":")
let sunClose:[String] = attraction["OpeningHours"]["Sunday"]["To"].string!.componentsSeparatedByString(":")
XCTAssertEqual(monOpen, ["1","2","3"], "")
}
}
}
}

func testNativeBinding() {
measureBlock { () -> Void in
for _ in 0 ..< 400 {
autoreleasepool {
var monOpen:[String] = []
var monClose:[String] = []
var tueOpen:[String] = []
var tueClose:[String] = []
var wedOpen:[String] = []
var wedClose:[String] = []
var thuOpen:[String] = []
var thuClose:[String] = []
var friOpen:[String] = []
var friClose:[String] = []
var satOpen:[String] = []
var satClose:[String] = []
var sunOpen:[String] = []
var sunClose:[String] = []
var openDescription:String = ""

if let attractionsArray = orgJson as? NSArray{
if let attraction = attractionsArray[0] as? NSDictionary{
if let openHours = attraction["OpeningHours"] as? NSDictionary{
if let day = openHours["Monday"] as? NSDictionary{
if let open = day["From"] as? String{
monOpen = open.componentsSeparatedByString(":")
}
if let close = day["To"] as? String{
monClose = close.componentsSeparatedByString(":")
}
}
if let day = openHours["Tuesday"] as? NSDictionary{
if let open = day["From"] as? String{
tueOpen = open.componentsSeparatedByString(":")
}
if let close = day["To"] as? String{
tueClose = close.componentsSeparatedByString(":")
}
}
if let day = openHours["Wednesday"] as? NSDictionary{
if let open = day["From"] as? String{
wedOpen = open.componentsSeparatedByString(":")
}
if let close = day["To"] as? String{
wedClose = close.componentsSeparatedByString(":")
}
}
if let day = openHours["Thursday"] as? NSDictionary{
if let open = day["From"] as? String{
thuOpen = open.componentsSeparatedByString(":")
}
if let close = day["To"] as? String{
thuClose = close.componentsSeparatedByString(":")
}
}
if let day = openHours["Friday"] as? NSDictionary{
if let open = day["From"] as? String{
friOpen = open.componentsSeparatedByString(":")
}
if let close = day["To"] as? String{
friClose = close.componentsSeparatedByString(":")
}
}
if let day = openHours["Saturday"] as? NSDictionary{
if let open = day["From"] as? String{
satOpen = open.componentsSeparatedByString(":")
}
if let close = day["To"] as? String{
satClose = close.componentsSeparatedByString(":")
}
}
if let day = openHours["Sunday"] as? NSDictionary{
if let open = day["From"] as? String{
sunOpen = open.componentsSeparatedByString(":")
}
if let close = day["To"] as? String{
sunClose = close.componentsSeparatedByString(":")
}
}
if let desc = openHours["OpeningHoursGenericExceptions"] as? String{
openDescription = desc
}
}
}
}
XCTAssertEqual(monOpen, ["1","2","3"], "")
}
}
}
}
func testJSONBinding() {
measureBlock { () -> Void in
for _ in 0 ..< 400 {
autoreleasepool {
var monOpen:[String] = []
var monClose:[String] = []
var tueOpen:[String] = []
var tueClose:[String] = []
var wedOpen:[String] = []
var wedClose:[String] = []
var thuOpen:[String] = []
var thuClose:[String] = []
var friOpen:[String] = []
var friClose:[String] = []
var satOpen:[String] = []
var satClose:[String] = []
var sunOpen:[String] = []
var sunClose:[String] = []
var openDescription:String = ""

let openHours = json[0]["OpeningHours"]
var day:JSON

day = openHours["Monday"]
if let open = day["From"].string {
monOpen = open.componentsSeparatedByString(":")
}
if let close = day["To"].string {
monClose
= close.componentsSeparatedByString(":")
}
day = openHours["Tuesday"]
if let open = day["From"].string {
tueOpen = open.componentsSeparatedByString(":")
}
if let close = day["To"].string {
tueClose = close.componentsSeparatedByString(":")
}
day = openHours["WednesDay"]
if let open = day["From"].string {
wedOpen = open.componentsSeparatedByString(":")
}
if let close = day["To"].string {
wedClose = close.componentsSeparatedByString(":")
}
day = openHours["Thursday"]
if let open = day["From"].string {
thuOpen = open.componentsSeparatedByString(":")
}
if let close = day["To"].string {
thuClose = close.componentsSeparatedByString(":")
}
day = openHours["Friday"]
if let open = day["From"].string {
friOpen = open.componentsSeparatedByString(":")
}
if let close = day["To"].string {
friClose = close.componentsSeparatedByString(":")
}
day = openHours["Saturday"]
if let open = day["From"].string {
satOpen = open.componentsSeparatedByString(":")
}
if let close = day["To"].string {
satClose = close.componentsSeparatedByString(":")
}
day = openHours["Sunday"]
if let open = day["From"].string {
sunOpen = open.componentsSeparatedByString(":")
}
if let close = day["To"].string {
sunClose = close.componentsSeparatedByString(":")
}
XCTAssertEqual(monOpen, ["1","2","3"], "")
}
}
}
}

}

输出:

<unknown>:0: Test Case '-[JSONTestTests.JSONTestTests testJSONBinding]' measured [Time, seconds] average: 0.804, relative standard deviation: 5.592%, values: [0.835687, 0.814827, 0.819685, 0.841900, 0.764961, 0.845202, 0.691442, 0.779255, 0.818213, 0.830698], performanceMetricID:com.apple.XCTPerformanceMetric_WallClockTime, baselineName: "", baselineAverage: , maxPercentRegression: 10.000%, maxPercentRelativeStandardDeviation: 10.000%, maxRegression: 0.100, maxStandardDeviation: 0.100
<unknown>:0: Test Case '-[JSONTestTests.JSONTestTests testJSONSubscript]' measured [Time, seconds] average: 4.247, relative standard deviation: 3.496%, values: [4.019640, 4.004123, 4.146146, 4.194535, 4.487171, 4.300971, 4.310613, 4.408405, 4.318354, 4.279362], performanceMetricID:com.apple.XCTPerformanceMetric_WallClockTime, baselineName: "", baselineAverage: , maxPercentRegression: 10.000%, maxPercentRelativeStandardDeviation: 10.000%, maxRegression: 0.100, maxStandardDeviation: 0.100
<unknown>:0: Test Case '-[JSONTestTests.JSONTestTests testNativeBinding]' measured [Time, seconds] average: 0.223, relative standard deviation: 2.773%, values: [0.221099, 0.227395, 0.218860, 0.225989, 0.227128, 0.222370, 0.229956, 0.214535, 0.210818, 0.229868], performanceMetricID:com.apple.XCTPerformanceMetric_WallClockTime, baselineName: "", baselineAverage: , maxPercentRegression: 10.000%, maxPercentRelativeStandardDeviation: 10.000%, maxRegression: 0.100, maxStandardDeviation: 0.100
<unknown>:0: Test Case '-[JSONTestTests.JSONTestTests testNativeSubscript]' measured [Time, seconds] average: 0.362, relative standard deviation: 17.528%, values: [0.346285, 0.316185, 0.333650, 0.339416, 0.330243, 0.354034, 0.378730, 0.269519, 0.486904, 0.467607], performanceMetricID:com.apple.XCTPerformanceMetric_WallClockTime, baselineName: "", baselineAverage: , maxPercentRegression: 10.000%, maxPercentRelativeStandardDeviation: 10.000%, maxRegression: 0.100, maxStandardDeviation: 0.100
  • 你的 SwiftyJSON:4.247
  • 你的母语:0.223
  • 我的 SwiftyJSON:0.804
  • 我的母语:0.362

顺便说一句,如果我是你,我会这样做:

if let hours = orgJson[0]?["OpeningHours"] as? NSDictionary {
let openDescription = hours["OpeningHoursGenericExceptions"] as? String ?? ""
let monOpen = hours["Monday"]?["From"]??.componentsSeparatedByString?(":") as? [String] ?? []
let monClose = hours["Monday"]?["To"]??.componentsSeparatedByString?(":") as? [String] ?? []
let tueOpen = hours["Tuesday"]?["From"]??.componentsSeparatedByString?(":") as? [String] ?? []
let tueClose = hours["Tuesday"]?["To"]??.componentsSeparatedByString?(":") as? [String] ?? []
let wedOpen = hours["Wednesday"]?["From"]??.componentsSeparatedByString?(":") as? [String] ?? []
let wedClose = hours["Wednesday"]?["To"]??.componentsSeparatedByString?(":") as? [String] ?? []
let thuOpen = hours["Thursday"]?["From"]??.componentsSeparatedByString?(":") as? [String] ?? []
let thuClose = hours["Thursday"]?["To"]??.componentsSeparatedByString?(":") as? [String] ?? []
let friOpen = hours["Friday"]?["From"]??.componentsSeparatedByString?(":") as? [String] ?? []
let friClose = hours["Friday"]?["To"]??.componentsSeparatedByString?(":") as? [String] ?? []
let satOpen = hours["Saturday"]?["From"]??.componentsSeparatedByString?(":") as? [String] ?? []
let satClose = hours["Saturday"]?["To"]??.componentsSeparatedByString?(":") as? [String] ?? []
let sunOpen = hours["Sunday"]?["From"]??.componentsSeparatedByString?(":") as? [String] ?? []
let sunClose = hours["Sunday"]?["To"]??.componentsSeparatedByString?(":") as? [String] ?? []

// ...
}

它相当快速、安全且不那么复杂。


为什么 SwiftyJSON 很慢?

在访问 subscript 时,SwiftyJSON 会:

  1. 检查 key 是 String
  2. 再次用self[key:sub]下标
  3. 检查底层对象是 NSDictionary
  4. 使用提供的键下标 NSDictionary
  5. 用结果构造JSON对象
  6. 返回

也许编译器优化了一些步骤,但是“比native慢”有些不可避免:)

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

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com