Cannot call value of non-function type 'URLSession' error with mockURLSession - ios

I'm trying to unit test URLSession delegates with mockData. This is the delegate function that is being tested:
urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?)
This is the unit test so far:
func test_urlSession(){
let mockSession = MockURLSession(mockResponse: MockURLSession().successHttpURLResponse(request: self.urlRequest!) as! HTTPURLResponse)
//error here
sut?.urlSession(mockSession, task: MockURLSessionDataTask, didCompleteWithError: Error)
}
Whenever I try to inject the mockURLSession as a parameter the error:
Cannot call value of non-function type 'URLSession'
I'm testing for responses (ie 404, 200) that's why I'm injecting the mockURLSession with mocked responses. Any idea on how to inject the mockUrlSession into the delegate?
Edit___
protocol URLSessionDataTaskProtocol {
func resume()
}
protocol URLSessionProtocol {
typealias DataTaskResult = (Data?, URLResponse?, Error?) -> Void
func dataTask(with request: Request, completionHandler: #escaping DataTaskResult) -> URLSessionDataTaskProtocol
}
extension URLSession: URLSessionProtocol{
func dataTask(with request: Request, completionHandler: #escaping URLSessionProtocol.DataTaskResult) -> URLSessionDataTaskProtocol {
let task:URLSessionDataTask = dataTask(with: request, completionHandler: {
(data:Data?, response:URLResponse?, error:Error?) in completionHandler(data,response,error) }) as! URLSessionDataTask;
return task as URLSessionDataTaskProtocol
}
}
extension URLSessionDataTask: URLSessionDataTaskProtocol {}
class MockURLSession: URLSessionProtocol {
typealias DataTaskResult = (Data?, URLResponse?, Error?) -> Void
var nextDataTask = MockURLSessionDataTask()
var nextData: Data?
var nextError: Error?
private (set) var lastURL: URL?
private var mockResponse: HTTPURLResponse?
init() { }
init(mockResponse: HTTPURLResponse) {
self.mockResponse = mockResponse
}
func successHttpURLResponse(request: Request) -> URLResponse {
return HTTPURLResponse(url: request.url!, statusCode: 200, httpVersion: "HTTP/1.1", headerFields: nil)!
}
func wrongHttpURLResponse(request: Request, statusCode:Int) -> URLResponse {
return HTTPURLResponse(url: request.url!, statusCode: statusCode, httpVersion: "HTTP/1.1", headerFields: nil)!
}
func dataTask(with request: Request, completionHandler: #escaping DataTaskResult) -> URLSessionDataTaskProtocol {
lastURL = request.url
nextDataTask.resume()
if let mockResponse = mockResponse {
completionHandler(nextData, mockResponse, nextError)
}
else {
//default case is success
completionHandler(nextData, successHttpURLResponse(request: request), nextError)
}
return nextDataTask
}
}
class MockURLSessionDataTask: URLSessionDataTaskProtocol {
private (set) var resumeWasCalled = false
func resume() {
resumeWasCalled = true
}

Related

Custom NSURLProtocol with NSURLSession

I'm trying to implement this tutorial which implements a custom NSURLProtocol with NSURLConnection.
https://www.raywenderlich.com/76735/using-nsurlprotocol-swift
It works as expected, but now that NSURLConnection is deprecated in iOS9, I'm trying to convert it to NSURLSession.
Unfortunatly it didn't work.
I'm loading a website in uiwebview, if I use NSURLConnection it loads and everything work as expected, all http requests from the webview is captured, but not when using NSURLSession.
Any help is appreciated.
here is my code
import UIKit
class MyProtocol: NSURLProtocol, NSURLSessionDataDelegate, NSURLSessionTaskDelegate, NSURLSessionDelegate {
//var connection: NSURLConnection!
var mutableData: NSMutableData!
var response: NSURLResponse!
var dataSession: NSURLSessionDataTask!
override class func canInitWithRequest(request: NSURLRequest) -> Bool {
if NSURLProtocol.propertyForKey("MyURLProtocolHandledKey", inRequest: request) != nil {
return false
}
return true
}
override class func canonicalRequestForRequest(request: NSURLRequest) -> NSURLRequest {
return request
}
override class func requestIsCacheEquivalent(aRequest: NSURLRequest,
toRequest bRequest: NSURLRequest) -> Bool {
return super.requestIsCacheEquivalent(aRequest, toRequest:bRequest)
}
override func startLoading() {
let newRequest = self.request.mutableCopy() as! NSMutableURLRequest
NSURLProtocol.setProperty(true, forKey: "MyURLProtocolHandledKey", inRequest: newRequest)
self.dataSession = NSURLSession.sharedSession().dataTaskWithRequest(newRequest)
dataSession.resume()
self.mutableData = NSMutableData()
}
override func stopLoading() {
print("Data task stop")
self.dataSession.cancel()
self.mutableData = nil
}
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveResponse response: NSURLResponse, completionHandler: (NSURLSessionResponseDisposition) -> Void) {
self.response = response
self.mutableData = NSMutableData()
print(mutableData)
}
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) {
self.client?.URLProtocol(self, didLoadData: data)
self.mutableData.appendData(data)
}
func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) {
if (error == nil)
{
self.client!.URLProtocolDidFinishLoading(self)
self.saveCachedResponse()
}
else
{
self.client?.URLProtocol(self, didFailWithError: error!)
}
}
func saveCachedResponse () {
let timeStamp = NSDate()
let urlString = self.request.URL?.absoluteString
let dataString = NSString(data: self.mutableData, encoding: NSUTF8StringEncoding) as NSString?
print("TiemStamp:\(timeStamp)\nURL: \(urlString)\n\nDATA:\(dataString)\n\n")
}
}
I've solved it.
Here is the code if anyone needs it.
import Foundation
class MyProtocol1: NSURLProtocol, NSURLSessionDataDelegate, NSURLSessionTaskDelegate
{
private var dataTask:NSURLSessionDataTask?
private var urlResponse:NSURLResponse?
private var receivedData:NSMutableData?
class var CustomKey:String {
return "myCustomKey"
}
// MARK: NSURLProtocol
override class func canInitWithRequest(request: NSURLRequest) -> Bool {
if (NSURLProtocol.propertyForKey(MyProtocol1.CustomKey, inRequest: request) != nil) {
return false
}
return true
}
override class func canonicalRequestForRequest(request: NSURLRequest) -> NSURLRequest {
return request
}
override func startLoading() {
let newRequest = self.request.mutableCopy() as! NSMutableURLRequest
NSURLProtocol.setProperty("true", forKey: MyProtocol1.CustomKey, inRequest: newRequest)
let defaultConfigObj = NSURLSessionConfiguration.defaultSessionConfiguration()
let defaultSession = NSURLSession(configuration: defaultConfigObj, delegate: self, delegateQueue: nil)
self.dataTask = defaultSession.dataTaskWithRequest(newRequest)
self.dataTask!.resume()
}
override func stopLoading() {
self.dataTask?.cancel()
self.dataTask = nil
self.receivedData = nil
self.urlResponse = nil
}
// MARK: NSURLSessionDataDelegate
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask,
didReceiveResponse response: NSURLResponse,
completionHandler: (NSURLSessionResponseDisposition) -> Void) {
self.client?.URLProtocol(self, didReceiveResponse: response, cacheStoragePolicy: .NotAllowed)
self.urlResponse = response
self.receivedData = NSMutableData()
completionHandler(.Allow)
}
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) {
self.client?.URLProtocol(self, didLoadData: data)
self.receivedData?.appendData(data)
}
// MARK: NSURLSessionTaskDelegate
func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) {
if error != nil && error!.code != NSURLErrorCancelled {
self.client?.URLProtocol(self, didFailWithError: error!)
} else {
saveCachedResponse()
self.client?.URLProtocolDidFinishLoading(self)
}
}
// MARK: Private methods
/**
Do whatever with the data here
*/
func saveCachedResponse () {
let timeStamp = NSDate()
let urlString = self.request.URL?.absoluteString
let dataString = NSString(data: self.receivedData!, encoding: NSUTF8StringEncoding) as NSString?
print("TimeStamp:\(timeStamp)\nURL: \(urlString)\n\nDATA:\(dataString)\n\n")
}
}
Swift 3 version:
// CustomURLProtocol.swift
class CustomURLProtocol: URLProtocol, URLSessionDataDelegate, URLSessionTaskDelegate {
private var dataTask: URLSessionDataTask?
private var urlResponse: URLResponse?
private var receivedData: NSMutableData?
class var CustomHeaderSet: String {
return "CustomHeaderSet"
}
// MARK: NSURLProtocol
override class func canInit(with request: URLRequest) -> Bool {
guard let host = request.url?.host, host == "your domain.com" else {
return false
}
if (URLProtocol.property(forKey: CustomURLProtocol.CustomHeaderSet, in: request as URLRequest) != nil) {
return false
}
return true
}
override class func canonicalRequest(for request: URLRequest) -> URLRequest {
return request
}
override func startLoading() {
let mutableRequest = NSMutableURLRequest.init(url: self.request.url!, cachePolicy: NSURLRequest.CachePolicy.useProtocolCachePolicy, timeoutInterval: 240.0)//self.request as! NSMutableURLRequest
//Add User Agent
var userAgentValueString = "myApp"
mutableRequest.setValue(userAgentValueString, forHTTPHeaderField: "User-Agent")
print(mutableRequest.allHTTPHeaderFields ?? "")
URLProtocol.setProperty("true", forKey: CustomURLProtocol.CustomHeaderSet, in: mutableRequest)
let defaultConfigObj = URLSessionConfiguration.default
let defaultSession = URLSession(configuration: defaultConfigObj, delegate: self, delegateQueue: nil)
self.dataTask = defaultSession.dataTask(with: mutableRequest as URLRequest)
self.dataTask!.resume()
}
override func stopLoading() {
self.dataTask?.cancel()
self.dataTask = nil
self.receivedData = nil
self.urlResponse = nil
}
// MARK: NSURLSessionDataDelegate
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask,
didReceive response: URLResponse,
completionHandler: #escaping (URLSession.ResponseDisposition) -> Void) {
self.client?.urlProtocol(self, didReceive: response, cacheStoragePolicy: .notAllowed)
self.urlResponse = response
self.receivedData = NSMutableData()
completionHandler(.allow)
}
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
self.client?.urlProtocol(self, didLoad: data as Data)
self.receivedData?.append(data as Data)
}
// MARK: NSURLSessionTaskDelegate
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
if error != nil { //&& error.code != NSURLErrorCancelled {
self.client?.urlProtocol(self, didFailWithError: error!)
} else {
//saveCachedResponse()
self.client?.urlProtocolDidFinishLoading(self)
}
}
}
The problem you are having with your code is that you are using the the NSURLSession.sharedSession to contain your data task. By using the shared session, you are not able to change the session delegate so none of your delegate routines are going to be invoked.
You will need to create a custom session with your protocol established as the delegate for the session. Then, when asked to start loading you can create a data task in that session.

How to use singleton with Alamofire using Swift 3?

I am new in iOS and I am bit confused that how to use singleton with Alamofire and how singleton is important. I created a networkWrapper class in that I have written Alamofire post and get method, but I didn't use singleton.
How can I create a Wrapper class of Alamofire with singleton? How can I get all tricks that is really important?
Below is my code for wrapper class:
import Foundation
import UIKit
import Alamofire
import SwiftyJSON
class AFWrapper: NSObject {
//TODO :-
/* Handle Time out request alamofire */
class func requestGETURL(_ strURL: String, success:#escaping (JSON) -> Void, failure:#escaping (Error) -> Void)
{
Alamofire.request(strURL).responseJSON { (responseObject) -> Void in
//print(responseObject)
if responseObject.result.isSuccess {
let resJson = JSON(responseObject.result.value!)
//let title = resJson["title"].string
//print(title!)
success(resJson)
}
if responseObject.result.isFailure {
let error : Error = responseObject.result.error!
failure(error)
}
}
}
static func requestPOSTURL(_ strURL : String, params : [String : AnyObject]?, headers : [String : String]?, success:#escaping (JSON) -> Void, failure:#escaping (Error) -> Void){
Alamofire.request(strURL, method: .post, parameters: params, encoding: JSONEncoding.default, headers: headers).responseJSON { (responseObject) -> Void in
//print(responseObject)
if responseObject.result.isSuccess {
let resJson = JSON(responseObject.result.value!)
success(resJson)
}
if responseObject.result.isFailure {
let error : Error = responseObject.result.error!
failure(error)
}
}
}
}
In my controller:
if newLength == 6
{
let textZipCode = textField.text! + string
let dict = ["id" : "43","token": "2y103pfjNHbDewLl9OaAivWhvMUp4cWRXIpa399","zipcode" : textZipCode] as [String : Any]
//Call Service
AFWrapper.requestPOSTURL(HttpsUrl.Address, params: dict as [String : AnyObject]?, headers: nil, success: { (json) in
// success code
print(json)
}, failure: { (error) in
//error code
print(error)
})
setFields(city: "Ajmer", state: "Rajasthan", country: "India")
return newLength <= 6
}
I didn't look deep into your code. In swift we can create singleton by
static let sharedInstance = AFWrapper()
And it will create singleton instance of a class, so that class and static for singleton class instance functions are not necessary. Please refer below code for singleton class.
import Foundation
import UIKit
import Alamofire
import SwiftyJSON
class AFWrapper: NSObject {
static let sharedInstance = AFWrapper()
//TODO :-
/* Handle Time out request alamofire */
func requestGETURL(_ strURL: String, success:#escaping (JSON) -> Void, failure:#escaping (Error) -> Void)
{
Alamofire.request(strURL).responseJSON { (responseObject) -> Void in
//print(responseObject)
if responseObject.result.isSuccess {
let resJson = JSON(responseObject.result.value!)
//let title = resJson["title"].string
//print(title!)
success(resJson)
}
if responseObject.result.isFailure {
let error : Error = responseObject.result.error!
failure(error)
}
}
}
func requestPOSTURL(_ strURL : String, params : [String : AnyObject]?, headers : [String : String]?, success:#escaping (JSON) -> Void, failure:#escaping (Error) -> Void){
Alamofire.request(strURL, method: .post, parameters: params, encoding: JSONEncoding.default, headers: headers).responseJSON { (responseObject) -> Void in
//print(responseObject)
if responseObject.result.isSuccess {
let resJson = JSON(responseObject.result.value!)
success(resJson)
}
if responseObject.result.isFailure {
let error : Error = responseObject.result.error!
failure(error)
}
}
}
}
Now you can call Singleton class instance function by
AFWrapper.sharedInstance.requestPOSTURL(HttpsUrl.Address, params: dict as [String : AnyObject]?, headers: nil, success: { (json) in
// success code
print(json)
}, failure: { (error) in
//error code
print(error)
})
May be you need that :
import UIKit
import Alamofire
struct FV_API
{
//URL is http://www.stack.com/index.php/signup
static let appBaseURL = "" // assign your base url suppose: http://www.stack.com/index.php
static let apiSignUP = "" // assign signup i.e: signup
}
class APIManager: NSObject
{
//MARK:- POST APIs
class func postAPI(_ apiURl:String, parameters:NSDictionary, completionHandler: #escaping (_ Result:AnyObject?, _ Error:NSError?) -> Void)
{
var strURL:String = FV_API.appBaseURL // it gives http://www.stack.com/index.php and apiURl is apiSignUP
if((apiURl as NSString).length > 0)
{
strURL = strURL + "/" + apiURl // this gives again http://www.stack.com/index.php/signup
}
_ = ["Content-Type": "application/x-www-form-urlencoded"]
print("URL -\(strURL),parameters - \(parameters)")
let api = Alamofire.request(strURL,method: .post, parameters: parameters as? [String : AnyObject], encoding: URLEncoding.default)
// ParameterEncoding.URL
api.responseJSON
{
response -> Void in
print(response)
if let JSON = response.result.value
{
print("JSON: \(JSON)")
completionHandler(JSON as AnyObject?, nil)
}
else if let ERROR = response.result.error
{
print("Error: \(ERROR)")
completionHandler(nil, ERROR as NSError?)
}
else
{
completionHandler(nil, NSError(domain: "error", code: 117, userInfo: nil))
}
}
}
In other NSObject I made that method i.e for Signup:
class SignUp: NSObject
{
class func registerWithAPI(firstName: String, lastName:String, completionHandler: #escaping (_ Result:AnyObject?, _ Error:NSError?) -> Void)
{
let dict = NSMutableDictionary()
if !firstName.isEmpty
{
dict.setValue(firstName, forKey: "firstname")
}
if !lastName.isEmpty
{
dict.setValue(lastName, forKey: "lastname")
}
APIManager.postAPI(FV_API.apiSignUP, parameters: dict)
{
(Result, Error) -> Void in
completionHandler(Result, Error)
}
}
}
In controller class I made method to call api like:
func apiForSignup()
{
SignUp.registerWithAPI(firstName: txtFieldFirstName.text!, lastName: txtFieldLastName.text!)
{
(Result, Error) -> Void in
// write code
}

Swift 3 URLSession with URLCredential not working

I am doing a URLSession, but the URL requires credentials.
I have this whole method here that is trying to do a URLSession with URLCredentials:
func loginUser(_ username: String, password: String, completion: #escaping (_ result: Bool) -> Void)
{
//Create request URL as String
let requestString = String(format:"%#", webservice) as String
//Covert URL request string to URL
guard let url = URL(string: requestString) else {
print("Error: cannot create URL")
return
}
//Convert URL to URLRequest
let urlRequest = URLRequest(url: url)
print(urlRequest)
//Add the username and password to URLCredential
credential = URLCredential(user:username, password:password, persistence: .forSession)
//Setup the URLSessionConfiguration
let config = URLSessionConfiguration.default
//Setup the URLSession
let session = URLSession(configuration: config, delegate: self, delegateQueue: nil)
//Prepare the task to get data.
let task = session.dataTask(with: urlRequest, completionHandler: { (data, response, error) in
DispatchQueue.main.async(execute: {
if(error == nil)
{
completion(true)
}
else
{
completion(false)
}
})
})
//Run the task to get data.
task.resume()
}
and here are my URLSessionDelegate Methods:
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
if challenge.previousFailureCount > 0
{
completionHandler(Foundation.URLSession.AuthChallengeDisposition.cancelAuthenticationChallenge, nil)
}
else
{
completionHandler(Foundation.URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust:challenge.protectionSpace.serverTrust!))
}
}
/**
Requests credentials from the delegate in response to an authentication request from the remote server.
*/
func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
completionHandler(Foundation.URLSession.AuthChallengeDisposition.useCredential,credential)
}
I notice when I debug this in this delegate method:
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
if challenge.previousFailureCount > 0
{
completionHandler(Foundation.URLSession.AuthChallengeDisposition.cancelAuthenticationChallenge, nil)
}
else
{
completionHandler(Foundation.URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust:challenge.protectionSpace.serverTrust!))
}
}
That this method gets called twice and when it hits this line for the second time:
completionHandler(Foundation.URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust:challenge.protectionSpace.serverTrust!))
I get this error:
fatal error: unexpectedly found nil while unwrapping an Optional value
and then my app crashes! How do I fix this error?
the crash is due to challenge.protectionSpace.serverTrust being nil when you attempt to force unwrap it.
you should unwrap serverTrust and handle it being nil. my guess is that when serverTrust is nil challenge.error has a value.
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
if challenge.previousFailureCount > 0 {
completionHandler(Foundation.URLSession.AuthChallengeDisposition.cancelAuthenticationChallenge, nil)
} else if let serverTrust = challenge.protectionSpace.serverTrust {
completionHandler(Foundation.URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust: serverTrust))
} else {
print("unknown state. error: \(challenge.error)")
// do something w/ completionHandler here
}
}
Here is syntax as per swift 3.
Just verify firstly in which part of the delegate method it entered
open func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Swift.Void){
var disposition: URLSession.AuthChallengeDisposition = URLSession.AuthChallengeDisposition.performDefaultHandling
var credential:URLCredential?
if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
credential = URLCredential(trust: challenge.protectionSpace.serverTrust!)
if (credential != nil) {
disposition = URLSession.AuthChallengeDisposition.useCredential
}
else{
disposition = URLSession.AuthChallengeDisposition.performDefaultHandling
}
}
else{
disposition = URLSession.AuthChallengeDisposition.cancelAuthenticationChallenge
}
if (completionHandler != nil) {
completionHandler(disposition, credential);
}
}

NSOperationQueue with UIImage causes memory warning

I'm using NSOperationQueue to upload photos to a distant web-server, but when uploading more than 10 photos, memory warning appears and RAM used exceeds 150 Mo. Worst, once the photo picker has disappeared, the RAM is not deallocated... Here's the code used:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)) { () -> Void in
for i in 0..<self.assets.count {
let operation: SWSingleUploadOperation = SWUploadManager.sharedManager.operationForPhoto(self.assets[i].editedAsset!,
progress: { (progress: Float) -> Void in
self.updateCellForOperationIndex(i,
withState: .Uploading,
andProgress: progress)
},
completion: { (response: NSHTTPURLResponse?, error: NSError?) -> Void in
if response?.statusCode == 200 && error == nil {
self.updateCellForOperationIndex(i,
withState: .Success,
andProgress: 1.0)
}
else {
self.updateCellForOperationIndex(i,
withState: .Fail,
andProgress: 0.0)
}
})
operation.delegate = self
self.cellStates[NSIndexPath(forRow: i, inSection: 0)] = (state: .Uploading, progress: nil)
self.uploadOperations.append(operation)
self.uploadQueue?.addOperation(operation)
}
Here's the operationForPhoto method used below:
let photoData: NSData = UIImageJPEGRepresentation(photo, 0.8)!
return SWSingleUploadOperation(requestParameters: (uploadID: self.uploadParameters!.uploadID, data: photoData),
progressHandler: pProgress,
completionHandler: pCompletion)
And here's my NSOperation subclass content:
var delegate: SingleUploadOperationDelegate?
var requestParameters: (uploadID: String, data: NSData)?
var progressHandler: ((progress: Float) -> Void)?
var completionHandler: ((response: NSHTTPURLResponse?, error: NSError?) -> Void)?
weak var request: Alamofire.Request?
init(requestParameters: (sweebiId: String, data: NSData),
progressHandler: ((progress: Float) -> Void)?,
completionHandler: ((response: NSHTTPURLResponse?, error: NSError?) -> Void)?) {
self.requestParameters = requestParameters
self.progressHandler = progressHandler
self.completionHandler = completionHandler
super.init()
}
override func main() {
self.delegate?.uploadOperationDidStart(self)
self.request = Alamofire.upload(Router.AddImageToSweebi(sweebiId: self.requestParameters!.uploadID),
data: self.requestParameters!.data)
.validate()
.progress { (bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) -> Void in
self.progressHandler?(progress: Float(totalBytesWritten) / Float(totalBytesExpectedToWrite))
}
.response(completionHandler: { (request: NSURLRequest?, response: NSHTTPURLResponse?, data: NSData?, error: NSError?) -> Void in
self.requestParameters = nil
self.progressHandler = nil
self.completionHandler?(response: response, error: error)
self.completeOperation()
})
}
override func cancel() {
self.request?.cancel()
self.delegate?.uploadOperationDidCancel(self)
super.cancel()
}
Do you have any idea of why such RAM is used, and how to avoid this and deallocate it once the photo picker has been dismissed?

Thread 1: break point error to send post method

I would like to send post method (to login user) but when I click on login button in run time I got this message :
my class:
typealias ServiceResponse = (JSON, NSError?) -> Void
class RestApiManager: NSObject {
static let sharedInstance = RestApiManager()
let baseURL = "***********"
func login(body: [String: AnyObject],onCompletion: #escaping (JSON) -> Void) {
let route = baseURL+"o/token/"
makeHTTPPostRequest(path: route,body: body, onCompletion: { json, err in
onCompletion(json as JSON)
})
}
func getCategories(onCompletion: #escaping (JSON) -> Void) {
let route = baseURL+"o/token/"
makeHTTPGetRequest(path: route, onCompletion: { json, err in
onCompletion(json as JSON)
})
}
func getRandomUser(onCompletion: #escaping (JSON) -> Void) {
let route = baseURL
makeHTTPGetRequest(path: route, onCompletion: { json, err in
onCompletion(json as JSON)
})
}
// MARK: Perform a GET Request
private func makeHTTPGetRequest(path: String, onCompletion: #escaping ServiceResponse) {
let request = NSMutableURLRequest(url: NSURL(string: path)! as URL)
let session = URLSession.shared
let task = session.dataTask(with: request as URLRequest, completionHandler: {data, response, error -> Void in
if let jsonData = data {
let json:JSON = JSON(data: jsonData)
onCompletion(json, error as NSError?)
} else {
onCompletion(nil, error as NSError?)
}
})
task.resume()
}
// MARK: Perform a POST Request
private func makeHTTPPostRequest(path: String, body: [String: AnyObject], onCompletion: #escaping ServiceResponse) {
let request = NSMutableURLRequest(url: NSURL(string: path)! as URL)
// Set the method to POST
request.httpMethod = "POST"
do {
// Set the POST body for the request
let jsonBody = try JSONSerialization.data(withJSONObject: body, options: .prettyPrinted)
request.httpBody = jsonBody
let session = URLSession.shared
let task = session.dataTask(with: request as URLRequest, completionHandler: {data, response, error -> Void in
if let jsonData = data {
let json:JSON = JSON(data: jsonData)
onCompletion(json, nil)
} else {
onCompletion(nil, error as NSError?)
}
})
task.resume()
} catch {
// Create your personal error
onCompletion(nil, nil)
}
}
}
in my login controller :
//after click on login button
let parameters = ["grant_type": "password",
"username": "test29#gmail.com",
"password": "1",
"client_id": "toS899lbMGolv8j24piz0JI38VUCi6Mvzru27iBA",
"client_secret":"lG14Tk7m2mGYLMvBndW2yFZ1NGRLNrriIPH6gw30gAnMAcFMa5xJE3wP8H 4SDHAK0ND5nKIoSLZskFQQ1knEYiaPC3i5LNutPJlusiMNiuvhUHWnbvTCjmNkuCBkGgqO"]
RestApiManager.sharedInstance.login(body: parameters as [String : AnyObject]) { (json: JSON) in
print(json)
}
Try to put it back to the main thread:
func login(body: [String: AnyObject],onCompletion:#escaping(JSON) -> Void) {
let route = baseURL+"o/token/"
makeHTTPPostRequest(path: route,body: body, onCompletion: { json, err in
DispatchQueue.main.async {
onCompletion(json as JSON)
}
})
}

Resources