started learning swift two weeks ago, with no previous programming experience, and I can't for the life of me figure out why this wouldn't work to check for nil. it just crashes when trying to load a web page if the user enters an invalid URL. This is the ENTIRETY of the code.
import UIKit; import WebKit
class ViewController: UIViewController {
#IBOutlet weak var adressBar: UITextField!
#IBOutlet weak var webView: WKWebView!
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func returnPressed(_ sender: Any) {
if let adressBarText = adressBar.text {
if let myURL = URL(string: adressBarText) {
let myRequest = URLRequest(url: myURL)
webView.load(myRequest)
adressBar.resignFirstResponder()
print("EYYYYY")
} else {
print("BOOOO")
}
}
}
}
Try this method
func verifyUrl (urlString: String?) -> Bool {
//Check for nil
if let urlString = urlString {
// create NSURL instance
if let url = NSURL(string: urlString) {
// check if your application can open the NSURL instance
return UIApplication.sharedApplication().canOpenURL(url)
}
}
return false
}
https://stackoverflow.com/a/30130535/8069241
Related
I'm receiving notifications from Firebase in the AppDelegate class.
This notification contains a String named "notif_url". I've put this value in a var named "desired_url" and now I need to change my WebView url with the "desired_url" value.
But I can't access to the webview to change it url like this :
#IBOutlet weak var my_web_view: UIWebView!
func load_url(server_url: String){
let url = URL(string: server_url);
let request = URLRequest(url: url!);
my_web_view.loadRequest(request);
}
load_url(server_url: desired_url);
Do you know if I can do that and if yes, how ?
Images :
EDIT 1:
After adding breakPoint to know the wrong line, it seem't that the line is this one :
my_web_view.loadRequest(request)
EDIT 2:
If need, that's a part of my AppDelegate class code.
import UIKit
import UserNotifications
import Firebase
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
let gcmMessageIDKey = "gcm.message_id"
#IBOutlet weak var my_web_view: UIWebView!
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
return true
}
}
// [START ios_10_message_handling]
#available(iOS 10, *)
extension AppDelegate : UNUserNotificationCenterDelegate{
// Receive displayed notifications for iOS 10 devices.
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void){
print("Step : 12");
let userInfo = notification.request.content.userInfo
// Print message ID.
if let messageID = userInfo[gcmMessageIDKey]{
print("Message ID: \(messageID)")
}
// Print full message.
print(userInfo)
var url: String = userInfo[AnyHashable("url")] as! String;
load_url(server_url: url);
// Change this to your preferred presentation option
completionHandler([])
}
func load_url(server_url: String){
/*
let url = URL(string: server_url);
let request = URLRequest(url: url!);
my_web_view.loadRequest(request);
*/
guard let url = URL(string: server_url) else {
print("Invalid URL")
return
}
print("TRY : "+server_url);
let request = URLRequest(url: url)
my_web_view.loadRequest(request)
}
}
EDIT 3:
If need, that's my ViewController class code.
import Foundation
import UIKit
import SafariServices
import UserNotifications
class ViewController: UIViewController, UIWebViewDelegate{
#IBOutlet weak var my_web_view: UIWebView!
#IBOutlet weak var my_loading_view: UIView!
#IBOutlet weak var spinner : UIActivityIndicatorView!
#IBOutlet weak var app_logo : UIImageView!
#IBOutlet weak var deadlinePicker: UIDatePicker!
#IBOutlet weak var titleField: UITextField!
var new_url: String = "";
override func viewDidLoad(){
super.viewDidLoad()
let server_url = "https://www.sortirauhavre.com/";
NotificationCenter.default.addObserver(self, selector: #selector(self.rotated), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)
rotated();
spinner.startAnimating();
my_web_view.scrollView.bounces = false;
my_web_view.scrollView.isScrollEnabled = true;
let url = URL(string: server_url);
let request = URLRequest(url: url!);
my_web_view.loadRequest(request);
}
// CETTE FONCITON SE LANCE A LA ROTATION DE L'APPAREIL
func rotated(){
app_logo.center = my_loading_view.center;
let y = app_logo.frame.origin.y;
let h = app_logo.frame.size.height
app_logo.frame.origin.y = y-(h/2);
spinner.center = my_loading_view.center;
}
// CETTE FONCTION MET EN ARRIERE PLAN L'ANNIMATION DE CHARGEMENT
func removeLoader(){
self.view.addSubview(my_web_view);
}
// CETTE FONCTION MET EN PREMIER PLAN L'ANNIMATION DE CHARGEMENT
func addLoader(){
self.view.addSubview(my_loading_view);
}
// CETTE FONCTION SE DECLANCHE QUAND LES PAGES DE LA WEBVIEW COMMENCE A CHANGER
func webViewDidStartLoad(_ webView: UIWebView){
addLoader();
let server_url = "https://www.sortirauhavre.com/";
_ = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(ViewController.removeLoader), userInfo: nil, repeats: false);
if let text = webView.request?.url?.absoluteString{
if text.hasPrefix(server_url){
}
else if text != ""{
UIApplication.shared.openURL(URL(string: text)!)
my_web_view.goBack()
}
}
}
// CETTE FONCTION SE DECLANCHE QUAND LES PAGES DE LA WEBVIEW FINI DE CHANGER
func webViewDidFinishLoad(_ webView: UIWebView){
let server_url = "https://www.sortirauhavre.com/";
_ = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(ViewController.removeLoader), userInfo: nil, repeats: false);
if let text = webView.request?.url?.absoluteString{
if text.hasPrefix(server_url){
}
else if text != ""{
UIApplication.shared.openURL(URL(string: text)!)
my_web_view.goBack()
}
}
}
}
You are force unwrapping url which is not a valid URL. I would suggest adding a guard statement to prevent the crash if a invalid URL is created:
func load_url(server_url: String) {
guard let url = URL(string: server_url) else {
print("Invalid URL")
return
}
let request = URLRequest(url: url)
my_web_view.loadRequest(request)
}
As you are obtaining the URL in the AppDelegate you cannot simply update the UIWebView from this class. You will need to call a function in the my_web_view's parent class which updates the URL.
// App Delegate
var serverURL: String?
func load_url(server_url: String) {
serverURL = server_url
let notificationName = Notification.Name("updateWebView")
NotificationCenter.default.post(name: notificationName, object: nil)
}
// View Controller
override func viewDidLoad() {
let notificationName = Notification.Name("updateWebView")
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.updateWebView), name: notificationName, object: nil)
updateWebView()
}
func updateWebView() {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let serverURL = appDelegate.serverURL
guard let url = URL(string: serverURL) else {
print("Invalid URL")
return
}
let request = URLRequest(url: URL)
my_web_view.loadRequest(request)
}
Instead of creating a new instance of your view controller, or trying to duplicate the outlet, you just need to access the current instance of your view controller. You can use either:
A global value for the view controller, or
A singleton-like pattern.
Then you can access the instance from your app delegate, by calling either myGlobalViewController.webView or ViewController.instance.webView.
So, here's an example:
import UIKit
private var thisViewController: ViewController? // Will hold the instance.
class ViewController: UIViewController {
static var instance: ViewController {
guard let thisViewController = thisViewController else { fatalError() } // Don't do this unless you're 100% sure that you'll never access this before the instance is loaded.
return thisViewController
}
#IBOutlet weak var webView: UIWebView!
override func viewDidLoad() {
super.viewDidLoad()
thisViewController = self // Set the property to self.
}
...
}
After this, you can access the web view from your app delegate:
func load_url(server_url: String){
guard let url = URL(string: server_url) else {
return
}
let request = URLRequest(url: url)
ViewController.instance.webView.loadRequest(request)
}
As you can see in the Picture below there are edges.
When I embed the View with a NavigationView, than the edges appears. So how can I avoid this edges??
Thanks
import UIKit
class ShowSubmitViewController: UIViewController, UIWebViewDelegate {
#IBOutlet weak var webView: UIWebView!
var URL : String = ""
var type : Int = 0
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
loadBrowser()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func loadBrowser(){
switch type {
case 5:
let htmlString:String! = URL
webView.loadHTMLString(htmlString, baseURL: nil)
default:
let url = NSURL (string: URL);
let requestObj = NSURLRequest(URL: url!);
webView.loadRequest(requestObj);
}
}
}
Picture WebView with Edge
I installed FacebookSDK using Cocoapods, according to Terminal, I have installed FacebookSDK 4.8.0 (CoreKit, ShareKit and LoginKit), I imported the .h files in my BH-File.h, and already initialized everything in my AppDelegate.
For some reason, when trying to log in using a custom button, when I initialize FBLoginManager, I get an error Use of undeclared type "FBLoginManager".
this is my code
if (FBSDKAccessToken.currentAccessToken() == nil)
{
let fbLoginManager : FBSDKLoginManager =
fbLoginManager.logInWithReadPermissions(["public_profile", "email"], fromViewController: self, handler: { (loginResult, error) -> Void in
if error == nil {
print (FBSDKAccessToken.currentAccessToken().tokenString)
}
else {
print ("ERROR*****: \(error)")
}
})
}
What fixed to me was adding import FBSDKCoreKit and FBSDKLoginKit to my class, for some reason is not enough adding it in the BH-file.h
Try something like this, I just checked the code and it works (it's not exactly what you're looking for but I'm sure you can modify it as needed)
import UIKit
import FBSDKCoreKit
import FBSDKLoginKit
class ProfileViewController: UIViewController,FBSDKLoginButtonDelegate {
// #IBOutlet weak var nameLabel: UILabel!
#IBOutlet weak var nameLabel: UILabel!
#IBOutlet weak var imageView: UIImageView!
#IBOutlet weak var nextButton: UIButton!
#IBOutlet weak var fbLoginButton: FBSDKLoginButton!
override func viewDidLoad() {
super.viewDidLoad()
self.fbLoginButton.delegate = self
self.fbLoginButton.readPermissions = ["public_profile"]
self.fbLoginButton.publishPermissions = ["publish_actions"]
NSNotificationCenter.defaultCenter().addObserver(
self,
selector: "fbProfileChanged:",
name: FBSDKProfileDidChangeNotification,
object: nil)
FBSDKProfile.enableUpdatesOnAccessTokenChange(true)
// If we have a current Facebook access token, force the profile change handler
if ((FBSDKAccessToken.currentAccessToken()) != nil)
{
self.fbProfileChanged(self)
} }
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func prefersStatusBarHidden() -> Bool {
return true
}
//facebooks functions
func loginButton(loginButton: FBSDKLoginButton!, didCompleteWithResult result: FBSDKLoginManagerLoginResult!, error: NSError!) {
if (error != nil)
{
print( "\(error.localizedDescription)" )
}
else if (result.isCancelled)
{
// Logged out?
print( "Login Cancelled")
}
else
{
// Logged in?
print( "Logged in, segue now")
self.performSegueWithIdentifier("showHome", sender: self)
}
}
func loginButtonDidLogOut(loginButton: FBSDKLoginButton!) {
}
//see bitfountain
func fbProfileChanged(sender: AnyObject!) {
let fbProfile = FBSDKProfile.currentProfile()
if (fbProfile != nil)
{
// Fetch & format the profile picture
let strProfilePicURL = fbProfile.imagePathForPictureMode(FBSDKProfilePictureMode.Square, size: imageView.frame.size)
let url = NSURL(string: strProfilePicURL, relativeToURL: NSURL(string: "http://graph.facebook.com/"))
let imageData = NSData(contentsOfURL: url!)
let image = UIImage(data: imageData!)
self.nameLabel.text = fbProfile.name
self.imageView.image = image
self.nameLabel.hidden = false
self.imageView.hidden = false
self.nextButton.hidden = false
}
else
{
self.nameLabel.text = ""
self.imageView.image = UIImage(named: "")
self.nameLabel.hidden = true
self.imageView.hidden = true
}
}
#IBAction func nextButtonPressed(sender: UIButton) {
self.performSegueWithIdentifier("showHome", sender: self)
}
}
I created a view to use as background and I would like to change its color when label text is greater or less than variable number. The script is okay but the color is not changing.
Thanks in advance.
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var localName: UITextField!
#IBOutlet weak var localNameLabel: UILabel!
#IBOutlet weak var localTemp: UILabel!
#IBAction func getData(sender: AnyObject) {
getWeatherData("http://api.openweathermap.org/data/2.5/weather?q=" + localName.text! + "")
}
#IBOutlet weak var fundo: UIView!
override func viewDidLoad() {
super.viewDidLoad()
getWeatherData("http://api.openweathermap.org/data/2.5/weather?q=London")
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func getWeatherData(urlString: String){
let url = NSURL (string: urlString)
let task = NSURLSession.sharedSession().dataTaskWithURL(url!) { (data, response, error) in
dispatch_async(dispatch_get_main_queue(), {
self.setLabels(data!)
})
}
task.resume()
}
func setLabels(weatherData: NSData) {
do {
let json = try NSJSONSerialization.JSONObjectWithData(weatherData, options:NSJSONReadingOptions.MutableContainers) as! NSDictionary
print(json)
//localNameLabel.text = json[("name")] as? String
if let name = json[("name")] as? String {
localNameLabel.text = name
}
if let main = json[("main")] as? NSDictionary {
if let temp = main[("temp")] as? Double {
//convert kelvin to celsius
let ft = (temp - 273.15)
let myString = ft.description
localTemp.text = myString
self.changeColor()
}
}
} catch let error as NSError {
print(error)
}
var number : Float
func changeColor(){
number = 19.0
if(Float(localTemp.text!) < number){
fundo.backgroundColor = .blueColor()
}else{
fundo.backgroundColor = .orangeColor()
}
}
}
}
Edited to post the entire script
In your view controller you need to add UITextFieldDelegate which will allow you to access methods related to your text field. The top of your view controller should look like this:
class ViewController: UIViewController,UITextFieldDelegate //set delegate to class
You then need to set the delegate of your text field to self in viewDidLoad and add a target for when the text field changes:
override func viewDidLoad() {
super.viewDidLoad()
localTemp.delegate = self //set delegate to this vc
localTemp.addTarget(self, action: "textFieldDidChange:", forControlEvents: UIControlEvents.EditingChanged)
}
You can then implement this method which will run on every key press and you need to call your changeColor() method as above:
func textFieldDidChange(textField: UITextField) {
self.changeColor()
}
I'm not sure what I am missing here but I know it has to be simple. All I want to do is pass the updated UITextField to the other ViewControllers.
I have my important functions in ViewWillAppear so I don't think thats it. New to programming so I've never tried doing this before.
The code below: The greyViewController is where the user inputs the website of choice and the Pink and Blue View Controllers are where the code is shown. The blue and pink view Controllers call the hexStringFromData function to convert the website to code. What am I missing? I feel like I'm missing an IF statement but not sure where I would put it.
I've experimented with putting one in the greyViewController to set the UITextfield back to the Singleton var aurl to no avail. I'm sorry if its bad etiquette to post so much code, but I don't really know what I'm doing so I wouldn't know how to explain what trying to accomplish without posting it.
import Foundation
import UIKit
var globalHttpUrl: NSURL!
var aurl = NSString(string: "http://")
var url = NSURL(string: "\(aurl)\(globalHttpUrl)")
class SneakyViewController : UIViewController {
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
println(self.title)
func hexStringFromData(data: NSData) -> String {
var hexString = NSMutableString()
var buffer = [UInt8](count:data.length, repeatedValue:0)
data.getBytes(&buffer, length:data.length)
for var i=0; i<buffer.count; i++ {
if i % 4 == 0 && i != 0 {
hexString.appendString(" ")
}
hexString.appendFormat("%02x", buffer[i])
}
return hexString
}
}
func hexStringFromData(data: NSData) -> String {
var hexString = NSMutableString()
var buffer = [UInt8](count:data.length, repeatedValue:0)
data.getBytes(&buffer, length:data.length)
for var i=0; i<buffer.count; i++ {
if i % 4 == 0 && i != 0 {
hexString.appendString(" ")
}
hexString.appendFormat("%02x", buffer[i])
}
return hexString
}
}
class PinkViewController : SneakyViewController {
#IBOutlet weak var machineCode: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
let task = NSURLSession.sharedSession().dataTaskWithURL(url) {(data, response, error) in
var myText = NSString(data: data, encoding: NSASCIIStringEncoding)
dispatch_async(dispatch_get_main_queue()) {
self.machineCode.text = myText
}
}
//NSASCIIStringEncoding
task.resume()
}
override func viewWillAppear(animated: Bool) {
let task = NSURLSession.sharedSession().dataTaskWithURL(url) {(data, response, error) in
var myText = NSString(data: data, encoding: NSASCIIStringEncoding)
dispatch_async(dispatch_get_main_queue()) {
self.machineCode.text = myText
}
}
//NSASCIIStringEncoding
task.resume()
}
}
class GreyViewController : SneakyViewController, UITextFieldDelegate {
#IBOutlet var neoCodeView: UIView!
#IBOutlet weak var userInput: UITextField!
//var burl = NSString(string: "http://")
#IBAction func buttonPressed(sender: AnyObject) {
}
override func viewDidLoad() {
super.viewDidLoad()
userInput.clearsOnBeginEditing.description
userInput.clearButtonMode = UITextFieldViewMode.WhileEditing
}
#IBAction func goToPinkViewController(sender: AnyObject) {
globalHttpUrl = NSURL(string: self.userInput.text)
}
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
self.view.endEditing(true)
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
userInput.resignFirstResponder()
return true
}
override func viewWillAppear(animated: Bool) {
func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
self.view.endEditing(true)
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
userInput.resignFirstResponder()
return true
}
userInput.clearsOnBeginEditing.description
userInput.clearButtonMode = UITextFieldViewMode.WhileEditing
}
}
class BlueViewController : SneakyViewController {
#IBOutlet weak var humanCode: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
let task = NSURLSession.sharedSession().dataTaskWithURL(url) {(data, response, error) in
var length = data.length
var chunkSize = 1024 * 10
var offset = 0
while offset < length {
var currentChunkSize = length - offset>chunkSize ? chunkSize : length - offset
var chunk = NSData(bytes: data.bytes + offset, length:currentChunkSize)
offset += currentChunkSize
var string = self.hexStringFromData(chunk)
dispatch_sync(dispatch_get_main_queue()) {
self.humanCode.text = self.humanCode.text + string
}
}
}
task.resume()
}
override func viewWillAppear(animated: Bool) {
let task = NSURLSession.sharedSession().dataTaskWithURL(url) {(data, response, error) in
var myText = NSString(data: data, encoding: NSASCIIStringEncoding)
dispatch_async(dispatch_get_main_queue()) {
self.humanCode.text = myText
}
}
//NSASCIIStringEncoding
task.resume()
}
}
I think the problem lies with your declaration of url.
It will be instantiated when you first run the program, but won't be updated when globalHttpUrl is.
I think if you modified your code like below, it would work.
var url: NSURL {
get {
return NSURL(string: "\(aurl)\(globalHttpUrl)")
}
}