NSURLC подключение утечки в Swift
Я нашел несколько других статей о проблемах памяти с NSURLConnection, однако ни одна из них не имела отношения к проектам, использующим ARC. Моя проблема в том, что я делаю NSURLConnections каждые 0,5 с (да, я знаю, что было бы лучше с сокетами, но я не имею контроля над API). Когда я открываю инспектор отладки xCode, я ясно вижу рост используемой памяти:
Однако, когда я профилирую свое приложение с помощью инструментов - без утечек, без постоянного хранения между поколениями марок, просто ничего:
Я намеренно отделил всю свою другую логику и создал простое приложение, чтобы показать мою проблему.
Это основной (и единственный) ViewController
import UIKit
class ViewController: UIViewController {
private var timer: NSTimer!
private var requests = [ServerRequest]()
override func viewDidAppear(animated: Bool)
{
self.timer = NSTimer(timeInterval: 0.5, target: self, selector: "refresh", userInfo: nil, repeats: true)
NSRunLoop.mainRunLoop().addTimer(self.timer, forMode: NSRunLoopCommonModes)
}
@objc private func refresh()
{
let urlRequest = NSURLRequest(URL: NSURL(string: "https://api.stackexchange.com/2.2/questions?order=desc&sort=activity&site=stackru")!)
let serverRequest = ServerRequest(request: urlRequest){
[unowned self] result, error, request in
println("yaba daba duu")
self.requests.removeAll(keepCapacity: false)
}
requests.append(serverRequest)
serverRequest.send()
}
}
А вот мой делегат асинхронного соединения:
import Foundation
class ServerRequest: NSObject
{
private var request: NSURLRequest!
typealias completionType = (NSData?, NSError?, ServerRequest) -> ()
private var completion: completionType!
private var receivedData: NSMutableData?
private var connection: NSURLConnection?
init(request: NSURLRequest, completion: (NSData?, NSError?, ServerRequest) -> ())
{
super.init()
self.request = request
self.completion = completion
self.connection = NSURLConnection(request: self.request, delegate: self, startImmediately:false)
//this line will help connection is fired even while tere are touch events
self.connection?.scheduleInRunLoop(NSRunLoop.currentRunLoop(), forMode: NSRunLoopCommonModes)
NSURLCache.sharedURLCache().removeAllCachedResponses()
}
func send()
{
receivedData = NSMutableData()
self.connection?.start()
}
func abort()
{
self.connection?.cancel()
}
}
extension ServerRequest: NSURLConnectionDataDelegate, NSURLConnectionDelegate
{
func connection(connection: NSURLConnection, didReceiveResponse response: NSURLResponse)
{
self.receivedData?.length = 0
}
func connection(connection: NSURLConnection, didReceiveData data: NSData)
{
self.receivedData?.appendData(data)
}
func connection(connection: NSURLConnection, didFailWithError error: NSError)
{
self.connection = nil
self.completion(nil, error, self)
}
func connectionDidFinishLoading(connection: NSURLConnection)
{
self.connection = nil
self.completion(receivedData, nil, self)
}
//MARK: https specific(canAuthenticateAgainstProtectionSpace is depraceted first in iOS 8)
func connection(connection: NSURLConnection, canAuthenticateAgainstProtectionSpace protectionSpace: NSURLProtectionSpace) -> Bool
{
return protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust
}
func connection(connection: NSURLConnection, willSendRequestForAuthenticationChallenge challenge: NSURLAuthenticationChallenge)
{
challenge.sender.useCredential(NSURLCredential(forTrust: challenge.protectionSpace.serverTrust), forAuthenticationChallenge: challenge)
challenge.sender.continueWithoutCredentialForAuthenticationChallenge(challenge)
}
func connection(connection: NSURLConnection, willCacheResponse cachedResponse: NSCachedURLResponse) -> NSCachedURLResponse? {
return nil
}
}
Обратите внимание, что мне нужно подключиться к серверу https, поэтому мне нужны соответствующие методы делегата. Также я реализовал методы кэширования из-за некоторых предположений в SO, что кеширование ответов в NSURLConnection может вызвать мои проблемы. Наконец, запрос запланирован в режиме "NSRunLoopCommonModes", потому что он мне нужен во время прокрутки (хотя удаление этой строки в любом случае не влияет на проблему).
ОБНОВИТЬ
Я только что попробовал даже без пользовательского класса с делегатом, и результат почти такой же. Просто скопируйте и вставьте следующее:
import UIKit
class ViewController: UIViewController {
private var timer: NSTimer!
override func viewDidAppear(animated: Bool)
{
self.timer = NSTimer(timeInterval: 0.5, target: self, selector: "refresh", userInfo: nil, repeats: true)
NSRunLoop.mainRunLoop().addTimer(self.timer, forMode: NSRunLoopCommonModes)
}
@objc private func refresh()
{
let urlRequest = NSURLRequest(URL: NSURL(string: "https://api.stackexchange.com/2.2/questions?order=desc&sort=activity&site=stackru")!)
NSURLConnection.sendAsynchronousRequest(urlRequest, queue: NSOperationQueue.mainQueue())
{
response, data, error in
println("yaba daba duu")
}
}
}
И давление моей памяти снова растет