【问题标题】:Swift 2 nil NSURLSessionDataTask when adding configuration添加配置时Swift 2 nil NSURLSessionDataTask
【发布时间】:2016-04-30 22:02:03
【问题描述】:

session 设置为.init(configuration:..., delegate:self, delegateQueue:NSOperationQueue.mainQueue()) 用于代理服务器重定向时,NSURLSessionDataTask.resume() 不会导致执行task。当session 设置为.sharedSession() 时,task 按预期执行。

**kCFStreamPropertyHTTPProxyHost 等已被弃用。也许这会以阻止task 执行的方式影响NSURLSessionConfiguration

class ConnectionManager: NSURLSession, NSURLSessionDelegate {
    .
    .
    .
    if shouldUseProxy {
            let proxyEnable = NSNumber(int: 1) as CFNumber
            let  proxyDict: [NSObject:AnyObject] = [
                kCFNetworkProxiesHTTPEnable: proxyEnable,
                kCFStreamPropertyHTTPProxyHost: proxyHost,
                kCFStreamPropertyHTTPProxyPort: proxyPort,
                kCFStreamPropertyHTTPSProxyHost: proxyHost,
                kCFStreamPropertyHTTPSProxyPort: proxyPort,
                kCFProxyTypeKey: kCFProxyTypeHTTPS,
                kCFProxyUsernameKey: proxyUser,
                kCFProxyPasswordKey: proxyPW
            ]

            let config = NSURLSessionConfiguration.ephemeralSessionConfiguration()
            config.connectionProxyDictionary = proxyDict
            self.session = NSURLSession.init(configuration: config, delegate: self, delegateQueue: NSOperationQueue.mainQueue())
    } else {
        self.session = NSURLSession.sharedSession()
    }

        self.task = self.session.dataTaskWithRequest(request) {
            (data, response, error) in
            if error == nil {
                self.cookies = NSHTTPCookieStorage.sharedHTTPCookieStorage().cookiesForURL(response!.URL!)!

                self.httpResponse = (response as? NSHTTPURLResponse)!
                self.statusCode = (self.httpResponse!.statusCode)
                guard error == nil && data != nil else {
                    print(error)
                    return
                }

                do {
                    if self.statusCode == 200 {
                        self.contentsOfURL = try NSString(contentsOfURL: self.URL, encoding: NSUTF8StringEncoding) as String
                    }
                } catch {

                }
            }
        }

        self.task?.resume()
        .
        .
        .
}

【问题讨论】:

    标签: ios swift2 nsurlsession nsurlsessiondatatask


    【解决方案1】:

    设置配置

    在大多数情况下,除非您需要特殊配置,否则默认配置会起作用。

    let sessionConfiguration = NSURLSessionConfiguration.defaultSessionConfiguration()
    
    let session = NSURLSession(configuration: sessionConfiguration,
                               delegate: self,
                               delegateQueue: operationQueue)
    

    请参考 Apple 的文档:https://developer.apple.com/library/ios/documentation/Foundation/Reference/NSURLSession_class/#//apple_ref/doc/uid/TP40013435-CH1-SW7

    重定向响应

    NSURLSessionDelegate 具有以下提到的函数,该函数在发生重定向时被调用。

    func URLSession(session: NSURLSession, task: NSURLSessionTask, willPerformHTTPRedirection response: NSHTTPURLResponse, newRequest request: NSURLRequest, completionHandler: (NSURLRequest?) -> Void) {
        
        //self.completionHandler is some completion handler you have defined, it is call back function.
    
        if cancelled {
            self.completionHandler(nil, redirectRequest:nil, wasCancelled: true)
        }
        else {
            self.completionHandler(nil, redirectRequest:request, wasCancelled: false)
        }
        
        finished = true
        executing = false
    }
    

    有一个名为request 的参数包含新的URLRequest。现在你必须用这个新请求启动一个新的会话任务

    挑战

    这个函数是NSURLSessionDelegate 的一部分

    每当收到挑战时,都会调用以下函数。根据挑战的类型,您必须妥善处理。

    查看NSURLAuthenticationMethodHTTPBasicNSURLAuthenticationMethodHTTPDigest 的注释掉代码

    func URLSession(session: NSURLSession,
        didReceiveChallenge challenge: NSURLAuthenticationChallenge,
        completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void) {
            
            print("Challenge:")
            
            if(challenge.previousFailureCount == 0) {
                
                let credential = credentialForChallenge(challenge)
                print("Use Credential ....\n")
                completionHandler(.UseCredential, credential)
            }
            else {
                print("Previous Failure Count = \(challenge.previousFailureCount)")
                print("Cancelling Challenge\n")
                challenge.sender?.cancelAuthenticationChallenge(challenge)
            }
    }
    
    //Custom method to get the credential for the challenge
    //In your case you would be interested in NSURLAuthenticationMethodHTTPBasic
    func credentialForChallenge(challenge : NSURLAuthenticationChallenge) -> NSURLCredential? {
        
        //https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/URLLoadingSystem/Articles/AuthenticationChallenges.html
        //challenge knows:
        //what triggered the challenge
        //how many attempts were made for the challenge - previousFailureCount
        //any previous attempted credentials - proposedCredential
        //the NSURLProtectionSpace that requires the credentials
        //sender of the challenge
        
        //#Respond
        //Get authentication method
        
        let credential : NSURLCredential?
        
        print("Method = \(challenge.protectionSpace.authenticationMethod)")
        
        switch(challenge.protectionSpace.authenticationMethod) {
            
        case NSURLAuthenticationMethodHTTPBasic:
            //            HTTP basic authentication
            //            prompt user for username and password
            //            let credential = NSURLCredential(user: <#T##String#>, password: <#T##String#>, persistence: <#T##NSURLCredentialPersistence#>)
            credential = nil
            
            
        case NSURLAuthenticationMethodHTTPDigest:
            //            HTTP digest authentication
            //            prompt user for username and password
            //            let credential = NSURLCredential(user: <#T##String#>, password: <#T##String#>, persistence: <#T##NSURLCredentialPersistence#>)
            
            credential = nil
            
            
        case NSURLAuthenticationMethodClientCertificate:
            //            Client certificate authentication
            //            let credential = NSURLCredential(identity: <#T##SecIdentity#>, certificates: <#T##[AnyObject]?#>, persistence: <#T##NSURLCredentialPersistence#>)
            credential = nil
            
            
        case NSURLAuthenticationMethodServerTrust:
            //            Server trust authentication
            if let serverTrustExists = challenge.protectionSpace.serverTrust {
                credential = NSURLCredential(trust: serverTrustExists)
            }
            else {
                credential = nil
            }
            
        default:
            credential = nil
        }
        
        return credential
    }
    

    【讨论】:

    • 谢谢。问题是,由于 .resume() 等待一切完成,它继续到一个变量 all ,该变量在任务中获取它的值。所以我可以在自己的线程中执行任务,现在它可以工作了。但是,我无法让代理工作。我知道实现是有效的,因为我得到了 407,但用户名和密码不起作用。
    • 请查看更新后的答案(挑战部分)。在您的情况下,提出了需要处理的挑战
    猜你喜欢
    • 1970-01-01
    • 2016-05-11
    • 1970-01-01
    • 2019-02-11
    • 2015-08-31
    • 1970-01-01
    • 1970-01-01
    • 2017-04-24
    • 2014-01-22
    相关资源
    最近更新 更多