Ambiguous use of 'connection(_:didReceive:)' - swift

static let didReceiveResponseSelector : Selector = #selector((NSURLConnectionDataDelegate.connection(_:didReceive:)) as (NSURLConnectionDataDelegate) ->(NSURLConnection,URLResponse) -> ())
This code is returning error:
Ambiguous use of 'connection(_:didReceive:)'
I referred to the official evolution thread of Apple on GitHub, I respected the syntax but is not working:
Referencing the Objective-C selector of a method

NSURLConnectionDataDelegate is a protocol, you can't create a Selector using NSURLConnectionDataDelegate.connection(_:didReceive:), you must used an implementation of NSURLConnectionDataDelegate like :
class YourDelegateImplementation: NSURLConnectionDataDelegate {
public func connection(_ connection: NSURLConnection, didReceive data: Data) {
}
}
And then you can create a Selector like this :
let yourDelegate: YourDelegateImplementation = YourDelegateImplementation()
let yourSelector : Selector = #selector(yourDelegate.connection(_:didReceive:))

Don't cast the Selector:
let didReceiveResponseSelector = #selector(NSURLConnectionDelegate.connection(_:didReceive:))
It's also worth noting that the delegate function connection(_ connection: NSURLConnection, didReceive challenge: URLAuthenticationChallenge) has been deprecated in favor of connection(_ connection: NSURLConnection, willSendRequestFor challenge: URLAuthenticationChallenge).

solved, just add "?":
static let didReceiveResponseSelector : Selector = #selector((NSURLConnectionDataDelegate.connection(_:didReceive:)) as ((NSURLConnectionDataDelegate) -> (NSURLConnection,URLResponse) -> void)?)

Related

Error: Generic parameter 'T' could not be inferred.

I have a problem with calling this method:
func setUpFeedbackForm<T:UIViewController>(viewController: T,
viewForScreenshot: UIView,
completionHandler: #escaping () -> ())
where T:FeedbackFormDelegate { ... }
inside this wrapper function:
public class func setUpFeedbackFormWrapper(viewController: UIViewController,
viewForScreenshot: UIView,
completionHandler: #escaping () -> ()) {
setUpFeedbackForm(viewController: viewController,
viewForScreenshot: viewForScreenshot,
completionHandler: completionHandler)
}
I am getting error: Generic parameter 'T' could not be inferred. I do understand what the error means, but I don't know how to implement this call correctly. Also the reason why I have this wrapper is that I want to expose func setUpFeedbackForm to obj-c code and I can't import it directly to obj-c because of swift's generics.
Could you please show me the correct way of calling it?
You have two constraints on the viewController parameter that need to be satisfied when calling setUpFeedbackForm:
inheritance from UIViewController
conformance to FeedbackFormDelegate
, and setUpFeedbackFormWrapper satisfies only one, thus the compiler doesn't know what to do with the other one.
The problem is caused by a limitation of Swift which can't directly express variables/parameters that satisfy both class inheritance and protocol conformance, unless using generics, which breaks the Objective-C compatibility.
Thus a valid UIViewController<FeedbackFormDelegate> construct in Objective-C doesn't have a direct equivalent in Swift.
A workaround to this limitation is to declare a 3rd method that exposes the class inheritance and protocol conformance arguments as two distinct parameters, and call that method from both the Objective-C compatible and the Swift-only versions.
func setUpFeedbackForm<T:UIViewController>(viewController: T,
viewForScreenshot: UIView,
completionHandler: #escaping () -> ())
where T:FeedbackFormDelegate {
setupFeedbackFormImpl(viewController: viewController,
feedbackFormDelegate: viewController,
viewForScreenshot: viewForScreenshot, completionHandler: completionHandler)
}
func setupFeedbackFormImpl(viewController: UIViewController,
feedbackFormDelegate: FeedbackFormDelegate,
viewForScreenshot: UIView,
completionHandler: #escaping () -> ()) {
// actual code here
}
public func setUpFeedbackFormWrapper(viewController: UIViewController,
viewForScreenshot: UIView,
completionHandler: #escaping () -> ()) {
guard let feedbackFormDelegate = viewController as? FeedbackFormDelegate else {
// you can also report errors here, if you want to
// forbid runtime calls with controllers that are not FeedbackFormDelegate
return
}
setupFeedbackFormImpl(viewController: viewController,
feedbackFormDelegate: feedbackFormDelegate,
viewForScreenshot: viewForScreenshot,
completionHandler: completionHandler)
}
If we think in terms of SOLID programming, then this workaround follows the Interface Segregation Principle, as we receive one argument for the view controller stuff, and another one for the delegate stuff, even if they point to the same object behind.

How do I cast an __NSMallocBlock__ to its underlying type in Swift 3?

I had a trick to help test UIAlertController that worked in Swift 2.x:
extension UIAlertController {
typealias AlertHandler = #convention(block) (UIAlertAction) -> Void
func tapButtonAtIndex(index: Int) {
let block = actions[index].valueForKey("handler")
let handler = unsafeBitCast(block, AlertHandler.self)
handler(actions[index])
}
}
This fails under Swift 3.x with fatal error: can't unsafeBitCast between types of different sizes, which tempts me to believe there might be a way to make the cast work. Can anyone figure it out?
Found a solution that works in Swift 3.0.1
extension UIAlertController {
typealias AlertHandler = #convention(block) (UIAlertAction) -> Void
func tapButton(atIndex index: Int) {
if let block = actions[index].value(forKey: "handler") {
let blockPtr = UnsafeRawPointer(Unmanaged<AnyObject>.passUnretained(block as AnyObject).toOpaque())
let handler = unsafeBitCast(blockPtr, to: AlertHandler.self)
handler(actions[index])
}
}
}
(Originally, the block value was the actual block, not a pointer to the block—which you obviously can't cast to a pointer to AlertHandler)
My answer is based on #Robert Atkins's, but shorter.
The problem here is that, valueForKey returns a Any typed object, and because in Swift,
MemoryLayout<Any>.size == 32
MemoryLayout<AnyObjcBlockType>.size == 8
an assertion will be triggered in unsafeBitCast when casting between types of different sizes.
One work-around is to create an intermediate wrapper and transform back to raw pointer, which satisfies MemoryLayout<UnsafeRawPointer>.size == 8.
A much simpler way is to create an indirect reference directly using protocol AnyObject, relying on the fact that MemoryLayout<AnyObject >.size == 8, we can write following valid code:
typealias AlertHandler = #convention(block) (UIAlertAction) -> Void
func tapButton(atIndex index: Int) {
if let block = actions[index].value(forKey: "handler") {
let handler = unsafeBitCast(block as AnyObject, to: AlertHandler.self)
handler(actions[index])
}
}
If your UIAlertController is an action sheet you can modify Robert's answer to dismiss the UIAlertController before you executed the handler.
dismiss(animated: true, completion: {() in handler(self.actions[index])})
I was using this extension for testing and without this modification my assertions for presented view controller were failing.

Is this specialized use of NSURLConnection to handle self signed certs convertible to NSURLSession?

I have a self signed certificate in the VM I use to test my service. Using answers found in UIWebView to view self signed websites (No private api, not NSURLConnection) - is it possible? I was able to write functioning swift 2.0 code. Xcode 7 tells me that NSURLConnection is deprecated and I should use NSURLSession instead. None of my attempts to migrate this code succeeded, and none of the usual conversion scenarios described in other answers seem to apply.
If I create a new NSURLSession in order to handle the authentication challenge with my delegate methods, the other loads still happen on the sharedSession, and therefore fail.
var authRequest : NSURLRequest? = nil
var authenticated = false
var trustedDomains = [:] // set up as necessary
func webView(webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool {
if !authenticated {
authRequest = request
let urlConnection: NSURLConnection = NSURLConnection(request: request, delegate: self)!
urlConnection.start()
return false
}
else if isWebContent(request.URL!) { // write your method for this
return true
}
return processData(request) // write your method for this
}
func connection(connection: NSURLConnection, willSendRequestForAuthenticationChallenge challenge: NSURLAuthenticationChallenge) {
if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
let challengeHost = challenge.protectionSpace.host
if let _ = trustedDomains[challengeHost] {
challenge.sender!.useCredential(NSURLCredential(forTrust: challenge.protectionSpace.serverTrust!), forAuthenticationChallenge: challenge)
}
}
challenge.sender!.continueWithoutCredentialForAuthenticationChallenge(challenge)
}
func connection(connection: NSURLConnection, didReceiveResponse response: NSURLResponse) {
authenticated = true
connection.cancel()
webview!.loadRequest(authRequest!)
}
I was able to suppress the deprecation warning by adding this line before the first method. I would prefer a solution that replaces NSURLConnection but in the absence of that, this will have to do.
// hide NSURLConnection deprecation
#available(iOS, deprecated=9.0)

"Does not conform to protocol" error when extending different class

I'm attempting to test my own class by injecting objects that adapt the URLSession and URLSessionDataTask protocols. I'm extending NSURLSession and NSURLSessionDataTask to adopt those protocols so that I can use the existing objects normally, but use test objects in unit tests.
I have the following code, with the error commented:
typealias SessionHandler = (NSData?, NSURLResponse?, NSError?) -> Void
protocol URLSession {
func dataTaskWithURL(url: NSURL, completionHandler: SessionHandler) -> URLSessionDataTask
}
protocol URLSessionDataTask {
}
// Type 'NSURLSession' does not conform to protocol 'URLSession'
extension NSURLSession : URLSession {}
extension NSURLSessionDataTask : URLSessionDataTask {}
I understand the error, my protocol doesn't exactly match the method as implimented by NSURLSession. How do I fix this?
What I ended up doing was creating a protocol extension that creates the necessary method that NSURLSession requires.
extension NSURLSession : URLSession {
func dataTaskWithURL(url: NSURL, completionHandler: SessionHandler) -> URLSessionDataTask {
return dataTaskWithURL(url, completionHandler: completionHandler) as NSURLSessionDataTask
}
}

didReceiveAuthenticationChallenge delegate not getting called in Swift

I am trying a sample project with NSURLConnection.
import Foundation
import UIKit
class loginVC: ViewController, UITextFieldDelegate, NSURLConnectionDelegate, NSURLConnectionDataDelegate{
var webData: NSMutableData!
override func viewDidLoad() {
super.viewDidLoad()
webData = NSMutableData()
callWebService("testdentist#gmail.com", Password:"1")
}
func callWebService(userName:NSString, Password:NSString){
var strURl: NSURL = NSURL .URLWithString("")
var request: NSMutableURLRequest = NSMutableURLRequest(URL: strURl, cachePolicy:NSURLRequestCachePolicy.ReloadIgnoringLocalCacheData, timeoutInterval:60.0)
var postString: NSString = ""
postString = postString.stringByAppendingFormat("username=%#&password=%#", userName,Password)
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
request.HTTPMethod = ""
var connection: NSURLConnection = NSURLConnection(request: request, delegate:self)
connection.start()
}
//NSURLConnection webservice
func connection(connection: NSURLConnection!, didReceiveResponse response: NSURLResponse!){
// webData.length = 0
println("response")
}
func connection(connection: NSURLConnection!, didReceiveData data: NSData!){
println(data.length)
webData .appendData(data)
}
func connection(connection: NSURLConnection, didFailWithError error: NSError!){
println("error in connection")
}
func connectionDidFinishLoading(connection: NSURLConnection!){
var response: NSString = NSString(data: webData, encoding: NSUTF8StringEncoding)
println("response:\(response)")
if response != ""{
}
}
func connection(connection: NSURLConnection, didReceiveAuthenticationChallenge challenge: NSURLAuthenticationChallenge!){
var authentication: NSURLCredential = NSURLCredential.credentialWithUser("", password:"", persistence: NSURLCredentialPersistence.ForSession)
}
}
It seems all delegates are getting called except didReceiveAuthenticationChallenge delegate method.What i am missing.any help will be appreciated.thanks in advance
For iOS 8 and above, you must implement connection(_:willSendRequestForAuthenticationChallenge:). connection:didReceiveAuthenticationChallenge: is not called in iOS8, only in older operating systems.
So, to provide authentication in iOS8 and above, implement the method above and in there you must invoke one of the challenge-responder methods (NSURLAuthenticationChallengeSender protocol):
useCredential:forAuthenticationChallenge:
continueWithoutCredentialForAuthenticationChallenge:
cancelAuthenticationChallenge:
performDefaultHandlingForAuthenticationChallenge:
rejectProtectionSpaceAndContinueWithChallenge:
didReceiveAuthenticationChallenge is a method on NSURLConnectionDelegate, whilst the rest of your methods (except didFailWithError) are all NSURLConnectionDataDelegate methods. Are you implementing both protocols in your controller? It would perhaps help if you posted all your class' code.
i don't think the question is in those terms for new Swift 3.0..
I have a similar problem, a code regularly working under xcode7/ios7-8-9/Swift 2.2
Migration have produced:
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: (Foundation.URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
...
}
but does NOT work.
rewrite by hand:
func urlSession(_: URLSession,
didReceive challenge: URLAuthenticationChallenge,
completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
}
now it DOES work.
my two cents.