how can I get the source code from an URL on the logs?
This code is returning an error message on the logs instead of the HTML data.
Can you please help me and let me know what can I include/change?
Thank you!
import UIKit
class ViewController: UIViewController {
#IBOutlet var textField: UITextField!
#IBOutlet var display: UILabel!
#IBAction func send(_ sender: Any) {
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let url = URL (string: "https://www.weather-forecast.com/locations/London/forecasts/latest")!
let request = NSMutableURLRequest(url:url)
let task = URLSession.shared.dataTask (with:request as URLRequest) {
data, response, error in
if error != nil {
print (error!)
} else {
if let unrappedData = data {
let dataString = NSString(data: unrappedData, encoding: String.Encoding.utf8.rawValue)
print (dataString!)
}
}
}
task.resume()
}
}
We can get the html code from the URL like below,
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
DispatchQueue.global(qos: .background).async {
// Background Thread
let myURLString = "https://www.weather-forecast.com/locations/London/forecasts/latest"
guard let myURL = URL(string: myURLString) else {
print("Error: \(myURLString) doesn't seem to be a valid URL")
return
}
do {
let myHTMLString = try String(contentsOf: myURL, encoding: .ascii)
print("HTML : \(myHTMLString)")
} catch let error {
print("Error: \(error)")
}
DispatchQueue.main.async {
// Run UI Updates or call completion block
}
}
}
}
Related
I'm using Macaw to parse and render an SVG file gotten from the server.
Here's the source code: https://pastebin.com/g9vUCpGX
How can I accomplish this task?
class ViewController: UIViewController{
#IBOutlet weak var profileBadge: SVGView!
override func viewDidLoad() {
super.viewDidLoad()
let url = URL(string: "https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/couchdb.svg")!
if profileBadge != nil{
profileBadge.loadSVG(from: url)
}
}
}
extension SVGView {
func loadSVG(from url: URL) {
DispatchQueue.global().async {
guard let data = try? Data(contentsOf: url) else {
return
}
guard let svgString = String(data: data, encoding: .utf8) else {
return
}
let node = (try? SVGParser.parse(text: svgString)) ?? Group()
DispatchQueue.main.async {
print(node)
self.node = node
}
}
}
}
You may use XIB or Storyboard.. It works using like below.
import UIKit
import Macaw
import SnapKit
class ViewController: UIViewController{
var profileBadge: SVGView = SVGView()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(profileBadge)
profileBadge.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
let url = URL(string: "https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/couchdb.svg")!
if profileBadge != nil{
profileBadge.loadSVG(from: url)
}
}
}
extension SVGView {
func loadSVG(from url: URL) {
DispatchQueue.global().async {
guard let data = try? Data(contentsOf: url) else {
return
}
guard let svgString = String(data: data, encoding: .utf8) else {
return
}
let node = (try? SVGParser.parse(text: svgString)) ?? Group()
DispatchQueue.main.async {
print(node)
self.node = node
}
}
}
}
Was able to figure out the issue. :) profileBadge should've been a UIView not UIImageView. And in the Identity Inspector, Class should've been SVGView and Module should've been Macaw.
Update
I am trying to implement the web caching technique in swift. It will load url and show some data and save some data after caching. I am having the data already in my log after saving using coredata but i can not update existing webview with these extra data.
I am following the example from :
https://www.raywenderlich.com/76735/using-nsurlprotocol-swift
First time webview looks:
When the load table details clicked i have have called the startLoading() method in func connection(_ connection: NSURLConnection!, didFailWithError error: NSError!) in MyURLProtocol.swift class.
How i can update my current web content with this data to webview ?
The implementation in: BrowserViewController.swift
import UIKit
class BrowserViewController: UIViewController, UITextFieldDelegate {
#IBOutlet var textField: UITextField!
#IBOutlet var webView: UIWebView!
//MARK: IBAction
#IBAction func buttonGoClicked(_ sender: UIButton) {
if self.textField.isFirstResponder {
self.textField.resignFirstResponder()
}
self.sendRequest()
}
//MARK: UITextFieldDelegate
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
self.sendRequest()
return true
}
//MARK: Private
func sendRequest() {
if let text = self.textField.text {
// MyURLProtocol.startLoading()
// return
let sampleUrl="https://apple.com"
let url = URL(string:sampleUrl)
let request = URLRequest(url:url!)
self.webView.loadRequest(request)
}
}
}
In MyURLProtocol.swift, i have called the self.startLoading()
func connection(_ connection: NSURLConnection!, didFailWithError error: NSError!)
The method is look like :
override func startLoading() {
print("startLoading url \(self.request)")
// 1
let possibleCachedResponse = self.cachedResponseForCurrentRequest()
if let cachedResponse = possibleCachedResponse {
print("Serving response from cache")
// 2
let data = cachedResponse.value(forKey: "data") as! Data!
let mimeType = cachedResponse.value(forKey: "mimeType") as! String!
let encoding = cachedResponse.value(forKey: "encoding") as! String!
let jsonData = cachedResponse.value(forKey: "jsonData") as! String!
let response = URLResponse(url: self.request.url!, mimeType: mimeType, expectedContentLength: (data?.count)!, textEncodingName: encoding)
// 4
self.client!.urlProtocol(self, didReceive: response, cacheStoragePolicy: .notAllowed)
self.client!.urlProtocol(self, didLoad: data!)
self.client!.urlProtocolDidFinishLoading(self)
print("cache binaryData \(jsonData)")
} else {
// 5
print("Serving response from NSURLConnection")
let newRequest = (self.request as NSURLRequest).mutableCopy() as! NSMutableURLRequest
URLProtocol.setProperty(true, forKey: "MyURLProtocolHandledKey", in: newRequest)
self.connection = NSURLConnection(request: newRequest as URLRequest, delegate: self)
}
}
My data is in jsondata, i need to show this in my webview from saved data.
I'm trying to login and I'm doing tests right now and I'm trying when the log is correct I changed the title of the button but I get this error: value of type '(Any) -> ()' has no member ' SetTitle '. Then I leave you the code and a screenshot.
I need help because I'm blocked and I can not continue. All help will be appreciated. Thank you.
And this is my code
import UIKit
class LogViewController: UIViewController {
#IBOutlet weak var _username: UITextField!
#IBOutlet weak var _password: UITextField!
#IBAction func _login_button(_ sender: Any) {
let username = _username.text
let password = _password.text
if(username == "" || password == "")
{
return
}
DoLogin(username!, password!)
}
func DoLogin(_ user:String, _ psw:String)
{
let url = URL(string: "http://localhost/bill/userLogin.php")
let session = URLSession.shared
let request = NSMutableURLRequest(url: url!)
request.httpMethod = "POST"
let paramToSend = "username=" + user + "&password=" + psw
request.httpBody = paramToSend.data(using: String.Encoding.utf8)
let task = session.dataTask(with: request as URLRequest, completionHandler: {
(data, response, error) in
guard let _:Data = data else
{
return
}
let json:Any?
do
{
json = try JSONSerialization.jsonObject(with: data!, options: [])
}
catch
{
return
}
guard let server_response = json as? NSDictionary else
{
return
}
if let data_block = server_response["data"] as? NSDictionary
{
if let session_data = data_block["session"] as? String
{
let preferences = UserDefaults.standard
preferences.set(session_data, forKey: "session")
DispatchQueue.main.async {
execute:self.LoginDone()
}
}
}
})
task.resume()
}
func LoginDone()
{
_username.isEnabled = false
_password.isEnabled = false
_login_button.setTitle("Logout", for: .normal)
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
You have issue that is connected with _login_button because it is #IBAction not #IBOutlet.
For solving of this issue drag outlet from storyboard and connect it with proper file.
And than set property of the button.
Example.
#IBOutlet weak var _login_button_outlet: UIButton!
func LoginDone()
{
_username.isEnabled = false
_password.isEnabled = false
_login_button_outlet.setTitle("Logout", for: .normal)
}
hi you trying to set the title to the _login_button which not the button its the #IBAction method so for setting the title you have to create #IBOutlet weak var _login_button: UIButton!.
I have a log in page that collects a username and password. On submit, Its sends to the database to retrieve our servers access key. I do this through an asynchronous JSON POST using session.dataTask. When I retrieve the JSON Object I parse the key out of it. I want to pass it to the next page, retrieve a firebase token and then send both pieces of data back to the server for DB storage. I have created a "prepare for segue" function that collects the variable and passes it to a variable on the next page. I believe I am not setting up the sequence of events correctly or that the data isn't making it out of the Async container. Can someone have a look at these two files and see where I am getting it wrong?
Here is the first page I want to segue away from after making the REST web service call...
loginVC.swift:
import UIKit
class LoginVC: UIViewController {
#IBOutlet weak var username: UITextField!
#IBOutlet weak var password: UITextField!
#IBOutlet weak var validationBox: UITextView!
#IBAction func logInAction(_ sender: UIButton) {
guard let user = username.text, !user.isEmpty else {
validationBox.text = "Please enter valid credentials"
return
}
guard let pass = password.text, !pass.isEmpty else {
validationBox.text = "Please enter valid credentials"
return
}
let params = ["sUser": username.text!, "sPass": password.text!]
let url = URL(string: "restWebServiceURL")!
let session = URLSession.shared
var request = URLRequest(url: url)
request.httpMethod = "POST"
do {
request.httpBody = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
} catch let error {
print(error.localizedDescription)
}
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
let task = session.dataTask(with: request as URLRequest, completionHandler: { data, response, error in
guard error == nil else { return }
guard let data = data else { return }
do {
if let parsedJSON = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any] {
let parsedData = parsedJSON["d"] as! [String:Any]
let key = parsedData["key"] as! String
DispatchQueue.main.async {
print(key)
self.performSegue(withIdentifier: "FirebaseVC", sender: key)
}
}
} catch let error {
print(error.localizedDescription)
}
})
task.resume()
}
func sayHello() {
print("Hello!")
}
func sayGoodbye() {
print("Goodbye!")
}
override func viewDidLoad() {
super.viewDidLoad()
validationBox.text = "Ready..."
func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let FirebaseInit = segue.destination as? FirebaseVC {
if let sKey = sender as? String {
print("prepare - " + sKey)
FirebaseInit.sessionKey = sKey
}
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Here is the page I want to go to to receive the data access key ...
FirebaseVC.swift:
import UIKit
class FirebaseVC: UIViewController {
private var _sessionKey = String()
var sessionKey : String {
get { return _sessionKey }
set { _sessionKey = newValue }
}
#IBOutlet weak var sessionKeyTestBox: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
print(_sessionKey)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Feel free to suggest a better way to pass the data to the next page. Thanks...
It turns out I was correct in my assumption the the chain of events was off. Following the model suggested by #achrefGassoumi, I moved the datatask to a Singleton Service here:
import Foundation
struct CallWebService {
static let sharedInstance = CallWebService()
func logInToCaduceus(u: String, p: String, completion: #escaping (_ sKey: String) -> ()) {
let params = ["sUser": u, "sPass": p]
let url = URL(string: "https://telemed.caduceususa.com/ws/telemed.asmx/telemedLogin")!
let session = URLSession.shared
var request = URLRequest(url: url)
request.httpMethod = "POST"
do {
request.httpBody = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
} catch let error {
print(error.localizedDescription)
}
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
let task = session.dataTask(with: request as URLRequest, completionHandler: { data, response, error in
guard error == nil else { return }
guard let data = data else { return }
do {
if let parsedJSON = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any] {
let parsedData = parsedJSON["d"] as! [String:Any]
let key = parsedData["key"] as! String
DispatchQueue.main.async {
completion(key)
}
}
} catch let error {
print(error.localizedDescription)
}
})
task.resume()
}
}
Then my two controllers look like this:
LoginVC
import UIKit
class LoginVC: UIViewController {
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.destination.isKind(of: FirebaseVC.self)) {
let vc = segue.destination as! FirebaseVC
if let sKey = sender as? String {
vc.sessionKey = sKey
}
}
}
#IBOutlet weak var username: UITextField!
#IBOutlet weak var password: UITextField!
#IBOutlet weak var validationBox: UITextView!
#IBAction func logInAction(_ sender: UIButton) {
guard let user = username.text, !user.isEmpty else {
validationBox.text = "Please enter valid credentials"
return
}
guard let pass = password.text, !pass.isEmpty else {
validationBox.text = "Please enter valid credentials"
return
}
CallWebService.sharedInstance.logInToCaduceus(u: username.text!, p: password.text!, completion: {(sessionKey: String) -> Void in
print(sessionKey)
self.performSegue(withIdentifier: "FirebaseVC", sender: sessionKey)
}
)
}
override func viewDidLoad() {
super.viewDidLoad()
//validationBox.textAlignment = .center
validationBox.text = "Ready..."
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
AND THE receiving FirebaseVC
import UIKit
class FirebaseVC: UIViewController {
private var _sessionKey = String()
var sessionKey : String {
get { return _sessionKey }
set { _sessionKey = newValue }
}
#IBOutlet weak var sessionKeyTestBox: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
sessionKeyTestBox.text = _sessionKey
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
Excuse my (non-swift) Javascript terminology but essentially I moved the data call into a service and then place a callback method in the service with the completion method to ensure the the performSegue doesn't fire until the data has been received and parsed out. So when i submit the log in form data to the server the segue doesn't fire until that async call has been completed.
I am trying to serialize a GET request then make a movie object, then appending that movie object to a movies array which I will use to show info on the UI.
I am new and have struggled with this problem for some time now :(
If you look at the self.movies?.append(movie) shouldnt that work? I dont see any reasons as to when i try to get the first item i get fatal error index out of bounds which means I the Array is not filled yet.... Dont know what i am doing wrong :(
import UIKit
class ViewController: UIViewController {
var movies:[Movie]? = []
#IBOutlet weak var uiMovieTitle: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
getMovieData()
print(self.movies?.count)
setUI()
}
#IBAction func yesBtn(_ sender: UIButton) {
print(movies?[5].title ?? String())
}
#IBAction func seenBtn(_ sender: UIButton) {
}
#IBAction func noBtn(_ sender: UIButton) {
}
#IBOutlet weak var moviePoster: UIImageView!
let urlString = "https://api.themoviedb.org/3/discover/movie?api_key=935f539acbfed4b9e5534ddeed3fb57e&language=en-US&sort_by=popularity.desc&include_adult=false&include_video=false&page=1&with_genres=12"
func getMovieData(){
//Set up URL
let todoEndPoint: String = "https://api.themoviedb.org/3/discover/movie?api_key=935f539acbfed4b9e5534ddeed3fb57e&language=en-US&sort_by=popularity.desc&include_adult=false&include_video=false&page=1&with_genres=12"
guard let url = URL(string: todoEndPoint) else {
print("Cant get URL")
return
}
let urlRequest = URLRequest(url: url)
//Setting up session
let config = URLSessionConfiguration.default
let session = URLSession.shared
//Task setup
let task = session.dataTask(with: urlRequest) { (data, URLResponse, error) in
//Checking for errors
guard error == nil else{
print("Error calling GET")
print(error)
return
}
//Checking if we got data
guard let responseData = data else{
print("Error: No data")
return
}
self.movies = [Movie]()
do{//If we got data, if not print error
guard let todo = try JSONSerialization.jsonObject(with: responseData, options:.mutableContainers) as? [String:AnyObject] else{
print("Error trying to convert data to JSON")
return
}//if data is Serializable, do this
if let movieResults = todo["results"] as? [[String: AnyObject]]{
//For each movieobject inside of movieresult try to make a movie object
for moviesFromJson in movieResults{
let movie = Movie()
//If all this works, set variables
if let title = moviesFromJson["title"] as? String, let movieRelease = moviesFromJson["release_date"] as? String, let posterPath = moviesFromJson["poster_path"] as? String, let movieId = moviesFromJson["id"] as? Int{
movie.title = title
movie.movieRelease = movieRelease
movie.posterPath = posterPath
movie.movieId = movieId
}
self.movies?.append(movie)
}
}
}//do end
catch{
print(error)
}
}
////Do Stuff
task.resume()
}
func setUI(){
//uiMovieTitle.text = self.movies![0].title
//print(self.movies?[0].title)
}
}
my Movie class:
import UIKit
class Movie: NSObject {
var title:String?
var movieRelease: String?
var posterPath:String?
var movieId:Int?
var movieGenre:[Int] = []
//public init(title:String, movieRelease:String, posterPath:String,movieId:Int) {
// self.movieId = movieId
//self.title = title
//self.movieRelease = movieRelease
//self.posterPath = posterPath
//self.movieGenre = [movieGenre]
//}
}
getMovieData calls the network asynchronously. Your viewDidLoad invokes this, then calls setUI() - but the networking is still ongoing when setUI is called.
Instead, call setUI when the networking is complete - after the self.movies?.append(movie) line. The UI code will need to happen on the main thread. So...
for moviesFromJson... // your existing code
...
self.movies?.append(movie)
}
// Refresh UI now movies have loaded.
DispatchQueue.main.async {
setUI()
}
import UIKit
class ViewController: UIViewController {
var movies:[Movie]? = []
#IBOutlet weak var uiMovieTitle: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
getMovieDataCall(completionHandler: {data, error in self. getMovieDataCallBack(data: data, error: error)})
}
func getMovieDataCallBack(data: Data?, error: Error?) {
if error == nil {
let dictionary = try! JSONSerialization.jsonObject(with: data!, options: .allowFragments) as! Dictionary<String, AnyObject>
//do your appending here and then call setUI()
print("dictionaryMovie \(dictionary)")
} else {
showAlertView("", error?.localizedDescription)
}
}
func getMovieDataCall(completionHandler: #escaping (Data?, Error?) -> Void)){
//Set up URL
let todoEndPoint: String = "https://api.themoviedb.org/3/discover/movie?api_key=935f539acbfed4b9e5534ddeed3fb57e&language=en-US&sort_by=popularity.desc&include_adult=false&include_video=false&page=1&with_genres=12"
guard let url = URL(string: todoEndPoint) else {
print("Cant get URL")
return
}
let urlRequest = URLRequest(url: url)
//Setting up session
let config = URLSessionConfiguration.default
let session = URLSession.shared
//Task setup
let task = session.dataTask(with: urlRequest) { (data, URLResponse, error) in
if error != nil {
NSLog("GET-ERROR", "=\(error)");
completionHandler(nil, error)
} else {
let dataString = String(data: data!, encoding: String.Encoding(rawValue: String.Encoding.utf8.rawValue))
print(dataString!)
completionHandler(data, nil)
}
task.resume()
}
func setUI(){
}