Cocoa Swift: How to ensure WKWebView will load url request - cocoa

I'm implementing an WKWebView but when there is an issue with the network such slow network connection the WKWebView loads blank page. Here is my implementation:
func loadWebView() {
if let url = URL(string: self.urlLbl.stringValue){
let request = URLRequest.init(url: url)
let config = WKWebViewConfiguration()
self.webView = WKWebView(frame: self.customView.frame)
self.webView.navigationDelegate = self
self.webView.frame = customView.bounds
self.webView.autoresizingMask = [.width, .height]
self.webView.wantsLayer = true
self.webView.customUserAgent = userAgentStr
self.webView.load(request)
self.webView.layer?.backgroundColor = NSColor.green.cgColor
self.view.needsDisplay = true
self.webView.load(request)
webView.allowsBackForwardNavigationGestures = true
self.customView.addSubview(self.webView)
}
}
My question to you guys there is a way to know if the request load and if didn't there is a way to reload the request?
I'll really appreciate your help

Related

I want to load image Using method of NSURLConnectionDelegate and NSURLConnectionDataDelegate

I want to load images into connectionDidFinishLoading method and the method func connection(_connection: NSURLConnection, didReceive: Data) is not getting called
class ImageDownload: UIImageView,NSURLConnectionDelegate,NSURLConnectionDataDelegate
{
var imageSaved:UIImage!
var imageDownloaded:UIImage!
var connection2:NSURLConnection = NSURLConnection()
var data: NSMutableData = NSMutableData()
var urlstring:String = ""
var fileURL:URL!
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true) as NSArray
var pathPlist:String!
func downloadImage()
{
let imgdownload :String = "http://image.tmdb.org/t/p/w500" + urlstring
// let urlnew: NSURL = NSURL(string: imgdownload)!
//print(urlnew,"url")
let url: NSURL = NSURL(string: imgdownload)!
let request1: NSMutableURLRequest = NSMutableURLRequest(url: url as URL)
// let request2: NSMutableURLRequest = NSMutableURLRequest(url: urlnew as URL, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 60.0)
connection2 = NSURLConnection(request: request1 as URLRequest, delegate: self, startImmediately: false)!
connection2.start()
}
func setURL(url:String) -> Void
{
print(url,"url")
urlstring = url
let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
fileURL = documentsDirectory.appendingPathComponent(url)
print(fileURL,"fileurl")
if FileManager.default.fileExists(atPath: fileURL.path)
{
let image = UIImage(contentsOfFile: fileURL.path)
print("file exists")
self.image = image
}
else
{
downloadImage()
//let imgdownload :String = "http://image.tmdb.org/t/p/w500" + url
// let request = URL(string: imgdownload)
// let myUrl = NSURL(string: imgdownload)
//print("image loaded")
// self.image = self.imageSaved
}
}
func connection(_ connection: NSURLConnection, didReceive response: URLResponse)
{
print("in didReceive response\n")
self.data = NSMutableData()
}
func connection(_connection: NSURLConnection, didReceive: Data)
{
print("in didReceive data\n")
self.data.append(data as Data)
print(data,"image data is")
}
func connection(_ connection: NSURLConnection, didFailWithError error: Error)
{
print("connection error = \(error)")
}
func connectionDidFinishLoading(_ connection: NSURLConnection)
{
}
}*
I'm not familiar with the Swift syntax for NSURLConnection, so there's a nonzero chance I'm missing something subtle with the delegate method names, but off the top of my head, I see a couple of bigger problems:
Why are you using NSURLConnection in Swift? Every version of iOS that supports Swift also has NSURLSession. Just use the shared session, and your behavior will be almost identical to NSURLConnection.
You're using HTTP URLs. In all recent versions of iOS, you have to add special bits to your Info.plist if you want your app to be able to access HTTP URLs. I do not recommend doing that. Just use HTTPS.
You can get free TLS certs for HTTPS from Let's Encrypt. My guess is that as soon as you set that up and switch to an HTTPS URL, your problems will go away even with the existing code. But you should still be using NSURLSession.

How to implement graphql subscription using apollo ios client

I am trying to implement graphql subscription using apollo ios client. But not able to figure it out as lack of documentation examples.
Example given on apollo documentation is:
let apollo: ApolloClient = {
let configuration = URLSessionConfiguration.default
// Add additional headers as needed
configuration.httpAdditionalHeaders = ["Authorization": "Bearer <token>"] // Replace `<token>`
let url = URL(string: "http://localhost:8080/graphql")!
return ApolloClient(networkTransport: HTTPNetworkTransport(url: url, configuration: configuration))
}()
APOLLO IOS GUIDE: Creating a client
Implement the subscription in apollo ios graphql client by following below steps.
Using cocoapods:
pod 'Apollo'
pod 'Apollo/WebSocket'
pod install
To create client to support subscription and authentication. Add below code in AppDelegate.swift:
Websocket - we have to use WebSocketTransport and URLRequest
Authentication - we have to pass auth parameters in connection params connectingPayload to server. And for http we are passing it in headers as mentioned in question snippet.
SplitNetworkTransport- To combine both http and websocket to create client. we have to use httpNetworkTransport and webSocketNetworkTransport
lazy var apollo: ApolloClient = {
let authPayloads = [
"Authorization": "Bearer "
]
let configuration = URLSessionConfiguration.default
configuration.httpAdditionalHeaders = authPayloads
let map: GraphQLMap = authPayloads
let wsEndpointURL = URL(string: "ws://localhost:8080/subscriptions")!
let endpointURL = URL(string: "http://localhost:8080/api")!
let websocket = WebSocketTransport(request: URLRequest(url: wsEndpointURL), connectingPayload: map)
let splitNetworkTransport = SplitNetworkTransport(
httpNetworkTransport: HTTPNetworkTransport(
url: endpointURL,
configuration: configuration
),
webSocketNetworkTransport: websocket
)
return ApolloClient(networkTransport: splitNetworkTransport)
}()
I'm getting close. I was getting rejected for not having the correct headers in my Websocket upgrade. I ended up having to set them directly on the URLRequest object.
var apollo: ApolloClient? {
let authHeaders = ["X-Hasura-Access-Key": "<my_Key>", "Content-Type": "application/json"]
let configuration = URLSessionConfiguration.default
// Add additional headers as needed
configuration.httpAdditionalHeaders = authHeaders
//The string to my graph QL Server run by Hasure on AWS RDS.
let graphQLEndpoint = "http://<my_host>/v1alpha1/graphql"
let graphQLSubscriptionEndpoint = "ws://<my_host>/v1alpha1/graphql"
//Take my Ec2 Server string and make a URL for the graph QL and subscriptions
guard let httpURL = URL(string: graphQLEndpoint), let webSocketURL = URL(string: graphQLSubscriptionEndpoint) else {
return nil
}
let httpTransport = HTTPNetworkTransport(url: httpURL, configuration: configuration, sendOperationIdentifiers: false)
var request = URLRequest(url: webSocketURL)
request.setValue("<my_key>", forHTTPHeaderField: "X-Hasura-Access-Key")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let webSocketTransport = WebSocketTransport(request: request, sendOperationIdentifiers: false, connectingPayload: nil)
let splitTransport = SplitNetworkTransport(httpNetworkTransport: httpTransport, webSocketNetworkTransport: webSocketTransport)
//Initalize the APolloClient with that URL.
return ApolloClient(networkTransport: splitTransport)
}
The upgrade worked after that.
Here's my ApolloClient setup for just a web socket transport client:
let connectingPayload = ["authToken": accessToken]
let urlRequest = URLRequest(url: baseURL)
let webSocketTransport = WebSocketTransport(request: urlRequest, sendOperationIdentifiers: false, connectingPayload: connectingPayload)
let apollo = ApolloClient(networkTransport: webSocketTransport)

Swift 2 OSX How come session with proxy succeeds without authentication?

I'm making an NSURLRequest through a proxy host/port. It seems that the request is receiving the appropriate response. The only issue is that this proxy/port requires authentication. Why am I not being prompted to authenticate the proxy host?
func sendRequest() {
let request = NSMutableURLRequest(NSURL(string: "https://www.awebsite/login")
let params = "&username=\(username)&password=\(password)&okc_api=1"
request.HTTPBody = params.dataUsingEncoding(NSUTF8StringEncoding)
request.HTTPMethod = "POST"
let proxyDict:[NSObject:AnyObject] = [
kCFNetworkProxiesHTTPEnable: NSNumber(int: 1) as CFNumber,
kCFStreamPropertyHTTPProxyHost: "123.456.789.012",
kCFStreamPropertyHTTPProxyPort: 1234,
kCFStreamPropertyHTTPSProxyHost: "123.456.789.012",
kCFStreamPropertyHTTPSProxyPort: 1234,
kCFProxyTypeKey: kCFProxyTypeHTTP,
kCFProxyTypeKey: kCFProxyTypeHTTPS
]
let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
configuration.connectionProxyDictionary = proxyDict
let operationQueue = NSOperationQueue()
let session = NSURLSession(configuration: configuration, delegate: self, delegateQueue: operationQueue)
let task = session.dataTaskWithRequest(request) {
(data, response, error) in
do {
let responseHeaders = response as! NSHTTPURLResponse
let statusCode = responseHeaders.statusCode
let contentsOfURL = try NSString(contentsOfURL: URL, encoding: NSUTF8StringEncoding)
if contentsOfURL.containsString("p_home") {
print(statusCode)
print("LOGGED IN!")
} else {
print("FAILED LOGIN!")
}
print(statusCode)
} catch {
print(error)
}
}
task.resume()
}
The proxy's password is probably already stored in the system keychain already, so it isn't asking you again. To know for sure, you'd have to check in the proxy server's logs to see if the requests are coming in with proper authentication.

Testing if an url is valid or not to show/hide an image

var TestYou = "www,aa.com"
if let url = TestYou as? String {img.hidden = true}else{img.hidden = false}
I want to hide an image if an url is found. If it is not I want to show the image.
What do I have to do to fix it?
If I got that right from your "question" you are searching for something like this (do this in your AppDelegate):
if let url = NSURL(string: ("www.aa.com")) {
// check if your application can open the NSURL
if UIApplication.sharedApplication().canOpenURL(url){
img.hidden = true //hide image
} else {
img.hidden = false //show image
}
}

Can someone explain dispatch_async() for me in this scenario

I had the following method in a separate class:
class API: NSObject {
var data = NSData()
var delegate: APIProtocol?
func getItems(callback: (Array<Image>) -> ()) {
let urlPath: NSString = "http://localhost:3000/files"
let url = NSURL(string: urlPath)
let request = NSMutableURLRequest(URL: url)
request.HTTPMethod = "GET"
request.addValue("application/json", forHTTPHeaderField: "Accept")
let config = NSURLSessionConfiguration.defaultSessionConfiguration() as NSURLSessionConfiguration
let session = NSURLSession(configuration: config) as NSURLSession
var dataTask = NSURLSessionDataTask()
dataTask = session.dataTaskWithRequest(request) { (data, response, error) in
if (error == nil) {
println("API at URL \(url)")
let responseArray = NSJSONSerialization.JSONObjectWithData(data, options: .MutableContainers, error: nil) as NSArray
var images = Image[]()
for item: AnyObject in responseArray {
var location = Image(dict: item as NSDictionary)
images.append(location)
}
var img = images[0] as Image
callback(images)
//self.delegate?.didReceiveResponse(responseArray)
}
}
dataTask.resume()
}
}
I couldn't get my tableView to reload when calling self.tableView.reloadData() inside the callback() until I added the dispatch_async() around it.
My questions are:
1) Why wouldn't it work without it and is it the proper thing for me to do now that it's refreshing the tableView correctly?
2) Is there another way to get it working without having to add the dispatch on the main queue?
api.getItems() { (theArray) in
dispatch_async(dispatch_get_main_queue(), {
self.images = theArray
self.tableView.reloadData()
if (viaPullToRefresh) {
self.refreshControl.endRefreshing()
}
})
}
When creating a NSURLSession you can specify the delegate/completion queue. If you don't specify a queue
the session creates a serial operation queue for performing all
delegate method calls and completion handler calls.
So this means that your callbacks are called on a private serial queue. Now, all UI must be updated on the main queue, this is why tableView.reloadData() wasn't working.
To remove the dispatch call to the main_queue create the session like this
let session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration(), delegate: nil, delegateQueue: NSOperationQueue.mainQueue())

Resources