SwiftyJSON性能问题 [英] SwiftyJSON Performance Issues

查看:97
本文介绍了SwiftyJSON性能问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



使用Alamofire下载数据,这很好但解析很好带有SwiftyJson的json非常缓慢。为了查看库是否确实存在问题,我在许多地方重写了json解析数据。在下面的代码中,我正在分析大约400个旅游景点之一的开放时间。



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







Swifty方式:

 让openDescription:String = json [OpeningHours] [OpeningHoursGenericExceptions]。string! 
让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(:)
让friOpen:[String] = json [OpeningHours] [Friday] [From]。st ring!.componentsSeparatedByString(:)
let friClose:[String] = json [OpeningHours] [Friday] [To] .string!.componentsSeparatedByString(:)
让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(:)
让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 =

如果让attractionsArray = orgJson为? NSArray {
如果让吸引力= attractionsArray [0]为? NSDictionary {
如果让openHours = attraction [OpeningHours]为? NSDictionary {
如果让day = openHours [Monday]为? NSDictionary {
如果让open = day [From]为?字符串{
monOpen = open.componentsSeparatedByString(:)
}
如果让close = day [To]为?字符串{
monClose = close.componentsSeparatedByString(:)
}
}
如果让day = openHours [Tuesday]为? NSDictionary {
如果让open = day [From]为?字符串{
tueOpen = open.componentsSeparatedByString(:)
}
如果让close = day [To]为?字符串{
tueClose = close.componentsSeparatedByString(:)
}
}
如果让day = openHours [Wednesday]为? NSDictionary {
如果让open = day [From]为?字符串{
wedOpen = open.componentsSeparatedByString(:)
}
如果让close = day [To]为?字符串{
wedClose = close.componentsSeparatedByString(:)
}
}
如果让day = openHours [Thursday]为? NSDictionary {
如果让open = day [From]为?字符串{
thuOpen = open.componentsSeparatedByString(:)
}
如果让close = day [To]为?字符串{
thuClose = close.componentsSeparatedByString(:)
}
}
如果让day = openHours [Friday]为? NSDictionary {
如果让open = day [From]为?字符串{
friOpen = open.componentsSeparatedByString(:)
}
如果让close = day [To]为?字符串{
friClose = close.componentsSeparatedByString(:)
}
}
如果让day = openHours [Saturday]为? NSDictionary {
如果让open = day [From]为?字符串{
satOpen = open.componentsSeparatedByString(:)
}
如果让close = day [To]为?字符串{
satClose = close.componentsSeparatedByString(:)
}
}
如果让day = openHours [Sunday]为? NSDictionary {
如果让open = day [From]为?字符串{
sunOpen = open.componentsSeparatedByString(:)
}
如果让close = day [To]为?字符串{
sunClose = close.componentsSeparatedByString(:)
}
}
如果让desc = openHours [OpeningHoursGenericExceptions]为?字符串{
openDescription = desc
}
}
}
}

这只是被解析数据的一部分,所以应用程序中的性能非常明显。



我想问题是,我有吗错误地使用了SwiftyJSON还是这是预期的?

解决方案

首先,你的本土方式并不等同于Swifty方式。



SwiftyJSON版本有45 下标访问,但本机方式只有23 下标访问。



要使本机方式等效,它应该类似于:

 让openDescription = attraction [OpeningHours]![OpeningHoursGenericExceptions] as String 
let monOpen =(attraction [OpeningHours]![Monday] !! [From] as String).componentsSeparatedByString(:)
让monClose =(吸引力[OpeningHours]![Monday] !! [To] as Str ing).componentsSeparatedByString(:)
let tueOpen =(attraction [OpeningHours]![Tuesday] !! [From] as String).componentsSeparatedByString(:)
让tueClose =(吸引力[OpeningHours]![Tuesday] !! [To]! as String).componentsSeparatedByString(:)
// ... ...

或 Swifty方式应该像:

 让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 ]
如果让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],
星期二:[从:1:2:3,到:1:2:3],
星期三 :[From:1:2:3,To:1:2:3],
星期四:[From:1:2:3,To :1:2:3],
星期五:[从:1:2:3,到:1:2:3],
星期六:[从:1:2:3,到:1:2:3],
星期天:[从:1:2:3, To:1:2:3],
]
]
]
让json = JSON(orgJson)

类JSONTestTests: XCTestCase {

func testNativeSubscript(){
measureBlock {() - > _在$ 0中为

无效。< 400 {
autoreleasepool {
如果让attraction = orgJson [0]为? NSDictionary {
让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]![ 星期二] !! [To] as String).componentsSeparatedByString(:)
let wedOpen =(attraction [OpeningHours]![Wednesday] !! [From] as String ).componentsSeparatedByString(:)
let wedClose =(attraction [OpeningHours]![Wednesday] !! [To] as String).componentsSeparatedByString(:)
let thuOpe n =(吸引力[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 = (吸引力[OpeningHours]![Saturday] !! [From] as String).componentsSeparatedByString(:)
let satClose =(attraction [OpeningHours]![Saturday] !! [To] as String).componentsSeparatedByString(:)
让sunOpen =(attraction [OpeningHours]![Sunday] !! [From] as String).componentsSeparatedByString( :)
让sunClose =(吸引力[OpeningHours]![Sund ay] !! [To] as String).componentsSeparatedByString(:)
XCTAssertEqual(monOpen,[1,2,3],)
XCTAssertEqual (openDescription,test)
}
}
}
}
}

func testJSONSubscript(){
measureBlock {() - >对于_中的_,在
中无效。< 400 {
autoreleasepool {
let attraction = json [0]
let openDescription:String = attraction [OpeningHours] [OpeningHoursGenericExceptions]。string!
让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(:)
让thuClose :[String] = attraction [OpeningHours] [Thursday] [To] .string!.componentsSeparatedByString(:)
let friOpen:[String] = attraction [OpeningHours] [星期五] [From] .string!.componentsSeparatedByString(:)
let friClose:[String] = attraction [OpeningHours] [Friday] [To] .string!.componentsSeparatedByString (:)
让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 {() - >对于_中的_,在
中无效。< 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 = 如果让attractionsArray = orgJson为?

? NSArray {
如果让吸引力= attractionsArray [0]为? NSDictionary {
如果让openHours = attraction [OpeningHours]为? NSDictionary {
如果让day = openHours [Monday]为? NSDictionary {
如果让open = day [From]为?字符串{
monOpen = open.componentsSeparatedByString(:)
}
如果让close = day [To]为?字符串{
monClose = close.componentsSeparatedByString(:)
}
}
如果让day = openHours [Tuesday]为? NSDictionary {
如果让open = day [From]为?字符串{
tueOpen = open.componentsSeparatedByString(:)
}
如果让close = day [To]为?字符串{
tueClose = close.componentsSeparatedByString(:)
}
}
如果让day = openHours [Wednesday]为? NSDictionary {
如果让open = day [From]为?字符串{
wedOpen = open.componentsSeparatedByString(:)
}
如果让close = day [To]为?字符串{
wedClose = close.componentsSeparatedByString(:)
}
}
如果让day = openHours [Thursday]为? NSDictionary {
如果让open = day [From]为?字符串{
thuOpen = open.componentsSeparatedByString(:)
}
如果让close = day [To]为?字符串{
thuClose = close.componentsSeparatedByString(:)
}
}
如果让day = openHours [Friday]为? NSDictionary {
如果让open = day [From]为?字符串{
friOpen = open.componentsSeparatedByString(:)
}
如果让close = day [To]为?字符串{
friClose = close.componentsSeparatedByString(:)
}
}
如果让day = openHours [Saturday]为? NSDictionary {
如果让open = day [From]为?字符串{
satOpen = open.componentsSeparatedByString(:)
}
如果让close = day [To]为?字符串{
satClose = close.componentsSeparatedByString(:)
}
}
如果让day = openHours [Sunday]为? NSDictionary {
如果让open = day [From]为?字符串{
sunOpen = open.componentsSeparatedByString(:)
}
如果让close = day [To]为?字符串{
sunClose = close.componentsSeparatedByString(:)
}
}
如果让desc = openHours [OpeningHoursGenericExceptions]为?字符串{
openDescription = desc
}
}
}
}
XCTAssertEqual(monOpen,[1,2,3] ,)
}
}
}
}
func testJSONBinding(){
measureBlock {() - >对于_中的_,在
中无效。< 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 =

让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(:)
}
如果让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 ]
如果让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 :测试用例' -  [JSONTestTests.JSONTestTests testJSONBinding]'测量[时间,秒]平均值:0.804,相对标准d eviation:5.592%,值:[0.835687,0.814827,0.819685,0.841900,0.764961,0.845202,0.691642,0.777255,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:测试用例' - [JSONTestTests.JSONTestTests testJSONSubscript]'测量[时间,秒]平均值:4.247,相对标准偏差:3.496% ,值:[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:测试用例' - [JSONTestTests.JSONTestTests testNativeBinding]'测量[时间,秒]平均值:0.223,关联标准偏差:2.773%,值:[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:测试用例' - [JSONTestTests.JSONTestTests testNativeSubscript]'测量[时间,秒]平均值:0.362,相对标准偏差: 17.528%,值:[0.346285,0.316185,0.333650,0.339416,0.330243,0.354034,0.378730,0.265019,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






<顺便说一句,如果我是你,我会做类似的事情:

 如果让hours = orgJson [0]? [OpeningHours]为? NSDictionary {
让openDescription = hours [OpeningHoursGenericExceptions]为?字串?
让monOpen = hours [Monday]?[From] ??。componentsSeparatedByString?(:)为? [String] ?? []
让monClose = hours [Monday]?[To] ??。componentsSeparatedByString?(:)为? [String] ?? []
让tueOpen = hours [Tuesday]?[From] ??。componentsSeparatedByString?(:)为? [String] ?? []
让tueClose = hours [Tuesday]?[To] ??。componentsSeparatedByString?(:)as? [String] ?? []
let wedOpen = hours [Wednesday]?[From] ??。componentsSeparatedByString?(:)as? [String] ?? []
let wedClose = hours [Wednesday]?[To] ??。componentsSeparatedByString?(:)as? [String] ?? []
让thuOpen = hours [Thursday]?[From] ??。componentsSeparatedByString?(:)为? [String] ?? []
让thuClose = hours [Thursday]?[To] ??。componentsSeparatedByString?(:)为? [String] ?? []
让friOpen = hours [Friday]?[From] ??。componentsSeparatedByString?(:)为? [String] ?? []
让friClose = hours [Friday]?[To] ??。componentsSeparatedByString?(:)为? [String] ?? []
让satOpen = hours [Saturday]?[From] ??。componentsSeparatedByString?(:)为? [String] ?? []
让satClose =小时[星期六]?[To] ??。componentsSeparatedByString?(:)为? [String] ?? []
让sunOpen = hours [Sunday]?[From] ??。componentsSeparatedByString?(:)为? [String] ?? []
让sunClose = hours [Sunday]?[To] ??。componentsSeparatedByString?(:)为? [String] ?? []

// ...
}

这是合理快速,安全,不那么复杂。






为什么SwiftyJSON很慢?



下标访问权限时,SwiftyJSON会:


  1. 检查密钥是字符串

  2. 再次下标 self [key:sub]

  3. 检查基础对象 NSDictionary

  4. 下标 NSDictionary 使用提供的密钥

  5. 构造 JSON 结果对象

  6. return

也许编译器优化了一些步骤,但比本机慢有些不可避免:)


I'm having serious performance issues parsing JSON with SwiftyJson from our API and populating in core data.

The data is downloaded with Alamofire, wich works nicely but parsing the json with SwiftyJson is painfully slow. To see if the library really was the problem i rewrote the json parsing in one of the many places the data is parsed. In the code below I am parsing the opening hours of one of about 400 tourist attractions.

See the difference in these screenshots, 7,7 sec to 185 ms:

The Swifty way:

    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(":")

The native way:

    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
                }
            }
        }
    }

This is only part of the data being parsed so the performance is really noticeable in the app.

I guess the question is, have i used SwiftyJSON incorrectly or is this to be expected?

解决方案

First of all, your "native way" is not equivalent to "Swifty way".

SwiftyJSON version has 45 subscript accesses, but native way has only 23 subscript accesses.

To make "native way" equivalent, it should be something like:

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(":")
// ...

or "Swifty way" should be like:

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(":")
}
// ...


Anyway, Yes, SwiftyJSON is slow. Let's measure:

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"], "")
                }
            }
        }
    }

}

Outputs:

<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

  • Your SwiftyJSON: 4.247
  • Your Native: 0.223
  • My SwiftyJSON: 0.804
  • My Native: 0.362

By the way, if I were you, I would do something like:

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] ?? []

    // ...
}

It's reasonably fast, safe, not so complicated.


Why SwiftyJSON is slow?

On subscript access, SwiftyJSON does:

  1. check the key is String
  2. subscript again with self[key:sub]
  3. check the underlying object is NSDictionary
  4. subscript underlying NSDictionary with the supplied key
  5. construct JSON object with the result
  6. return

Maybe the compiler optimizes some steps, but "slower than native" is somewhat unavoidable :)

这篇关于SwiftyJSON性能问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆