我的 iOS 应用程序遇到了一些性能问题,这是我第一次使用 NSURLSession 和 NSURLRequest,虽然我试图尽可能多地通知自己,但我还是碰壁了调试我面临的性能问题。
所以这就是我得到的:我有一个用 Swift 2 编写的 iOS 9 应用程序,我正在通过 Get、Post 和 Put Http 请求与 NodeJS/Express 服务器通信,使用 NSURLRequest 和 NSURLMutableRequest。我正在发送请求以获取一组对象(总共不超过 12000 个字节),但是这些请求需要花费大量时间(有时长达一分钟)。我已将日志记录添加到 nodeJs 服务器,我可以看到处理请求的时间不超过 30 毫秒。
注意:我不确定这是否相关,但我正在使用单例“帮助程序”类来发出我所有的 api 请求并解析结果(保存身份验证令牌,解析 JSON 对象并将它们保存到核心数据,保存用户首选项到 NSUserDefaults 等),我使用的是单例,因此我可以静态访问它,并且我正在解析所有数据,而不在单例的属性中保存除服务器的 URL 和 NSURLSession 之外的任何内容。
这是我的代码的样子。
//On initialization of the helper class
private let session = NSURLSession.sharedSession()
func getAllObjects() {
let route = "api/someRoute"
let request = getRequest(route)
request.timeoutInterval = httpTimeout
session.dataTaskWithRequest(request, completionHandler: ResultingObjects).resume()
}
getRequest 方法返回一个格式化的 NSMutableURLRequest,如下所示:
func getRequest(route: String) -> NSMutableURLRequest {
let request = NSMutableURLRequest()
request.URL = NSURL(string: "\(serverUrl)/\(route)")!
request.HTTPMethod = "GET"
request.addValue("Bearer \(self.AuthenticationToken()!)", forHTTPHeaderField: "Authorization")
return request
}
完成处理程序将解析返回的对象并将解析后的对象通知主线程,如下所示:
private func ResultingObjects(data: NSData?, response: NSURLResponse?, error: NSError?) {
if let d = data {
if !isAuthorized(d){
return
}
do {
if let JSON = try NSJSONSerialization.JSONObjectWithData(d, options: []) as? NSDictionary {
if let message = JSON["message"] as? String {
if message == "Empty result" {
//- Return notification to be handled in main thread
notifyMainThread(NoObjectsFetched, payload: nil)
return
}
}
if let objcts = JSON["SomeObjects"] as? NSArray {
if let SomeObjects = parseResultingObjects(objcts) {
//- Return notification to be handled in main thread
notifyMainThread(ObjectsFetched, payload: ["payload": SomeObjects])
}
return
}
}
}
catch {
print("Error getting resulting objects")
}
}
else if let e = error {
print("\(e), could not process GET request")
}
}
我也尝试在主线程上解析结果对象,但这似乎没有什么区别。
如果你好奇,这就是我向主线程发送数据的方式:
private func notifyMainThread(notification: String, payload: AnyObject?) {
dispatch_async(dispatch_get_main_queue(), {
if let p = payload {
NSNotificationCenter.defaultCenter().postNotificationName(notification, object: nil,
userInfo: p as! [String: [MYMODEL]])
}
else {
NSNotificationCenter.defaultCenter().postNotificationName(notification, object: nil)
}
});
}
我发现了什么: 没有任何意义!我尝试过调试,但我无法确定问题出在哪里,当调试器点击我的“getAllObjects”方法时,服务器记录它接收并处理之前可能需要几秒钟(最多 45 秒)请求(通常需要大约 30 毫秒)。据我所知,所有请求类型都会发生这种情况。此外,一旦应用程序取回数据(超快),解析它需要很长时间(大约 4 秒),并且只有大约 11kbs。
我还尝试更改请求缓存策略,以防应用程序与服务器检查缓存记录的有效性,我使用了 ReloadIgnoringLocalAndRemoteCachedData也不起作用。
现在,这听起来像是内存泄漏 如果我在任何时候暂停应用程序(使用它几分钟后),我可以看到相关数量的线程。老实说,我对 IOS 不太熟悉,所以我不确定这些线程是来自模拟器还是它们都属于应用程序,应用程序在 AVPlayer 类中流式传输视频内容(没有延迟问题),我相信许多这些线程都与此有关,但是我不确定这是否正常,这是我的意思的屏幕截图(注意滚动条 T_T)屏幕截图
可能是我有内存泄漏或一些僵尸线程大大降低了我的应用程序的性能?唯一真正明显的延迟仅发生在 HTTP 请求上,这很奇怪,我的 UI 的其他部分没有滞后,我的应用程序中的其他功能也没有受到性能问题的影响(甚至是来自 url 的流式视频内容)。
分析此性能问题以查明问题根源的最佳方法是什么?
更新 1: 感谢 Scriptable 的建议,我设法解决了线程问题(由多个 AVPlayer 做他们的事情引起)。然而,请求的性能并没有得到解决。
值得指出的是,服务器实际上与我发出请求的国家/地区位于同一国家/地区,当从浏览器发出请求或从命令行发出请求时,请求几乎是立即的。
此外,当我随机暂停应用程序(等待请求发生时)我可以在某些线程中看到“mach_msg_trap”,我对此并不熟悉,但我相信这可能是一种竞争条件?还是僵局?