I have been trying to make a web browser in Swift and it has not been going well.
I was wondering why I got errors whenever I typed webView.delegate = self.
import UIKit
class MapViewController: UIViewController {
#IBOutlet weak var searchBar: UISearchBar!
#IBAction func back(sender: AnyObject) {
webView.goBack()
}
#IBOutlet weak var menuButton:UIBarButtonItem!
#IBOutlet weak var webView: UIWebView!
func searchBarSearchButtonClicked(searchBar: UISearchBar!) {
searchBar.resignFirstResponder()
var text = searchBar.text
var url = NSURL(string: text) //type "http://www.apple.com"
var req = NSURLRequest(URL:url!)
self.webView!.loadRequest(req)
}
override func viewDidLoad() {
super.viewDidLoad()
//problem here
webView.delegate = self;
webView.keyboardDisplayRequiresUserAction = true
//problem down here
webView.frame = self.view.frame;
let url = NSBundle.mainBundle().URLForResource("index", withExtension:"html")
let request = NSURLRequest(URL: url!)
webView.loadRequest(request)
// var url = NSURL(string:"http://www.google.com")
// var req = NSURLRequest(URL:url!)
// self.webView!.loadRequest(req)
self.searchBar.delegate = self
if self.revealViewController() != nil {
menuButton.target = self.revealViewController()
menuButton.action = "revealToggle:"
self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
You are assigning self as the delegate, but your class does not implement the UIWebViewDelegate protocol.
class MapViewController: UIViewController, UIWebViewDelegate {
Related
I try to pass an image from one ViewController1 to another ViewController2 when a button is tapped. I am using segues in my Storyboard.
ViewController1
import UIKit
class ViewController: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
var imagePicker: UIImagePickerController!
#IBAction func editPhoto(_ sender: UIButton) {
let editViewController = storyboard?.instantiateViewController(withIdentifier: "EditImageViewController") as! EditImageViewController
editViewController.imageForEdit = imageView.image!
print(imageView)
print(imageView.image!)
navigationController?.pushViewController(editViewController, animated: true)
}
#IBOutlet weak var imageView: UIImageView! {
didSet {
imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true
}
}
override func viewDidLoad() {
super.viewDidLoad()
// 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.
}
}
print(imageView) results in
some(UIImageView: 0x7fc34df0e630; frame = (8 29; 303 443); clipsToBounds = YES; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = CALayer: 0x60000023e520)
and print(imageView.image!) in
size {3000, 2002} orientation 0 scale 1.000000
ViewController2
import UIKit
class EditImageViewController: UIViewController {
var imageForEdit = UIImage()
#IBOutlet weak var editingImage: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
editingImage.image = imageForEdit
print(imageForEdit)
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
print(imageForEdit) results in
size {0, 0} orientation 0 scale 1.000000
Why is that? Why isnt the image passed to ViewController2?
It seems to me that this could be a lot simpler. If you're using a Storyboard with a segue, you can easily accomplish this in prepare(for segue: UIStoryboardSegue, sender: Any?). Here's a sample storyboard:
In this case, ViewController has a segue on the Edit Image button to the EditImageViewController.
When you push that button, you get your prepare(for segue: call. Here's a sample ViewController:
class ViewController: UIViewController {
var imagePath = Bundle.main.path(forResource: "icon8", ofType: "png")
var anEditableImage:UIImage?
override func viewDidLoad() {
super.viewDidLoad()
if let imagePath = imagePath {
anEditableImage = UIImage(contentsOfFile: imagePath)
}
}
// MARK: - Navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destination = segue.destination as? EditImageViewController {
destination.imageForEdit = anEditableImage
}
}
}
And here's the EditImageViewController:
class EditImageViewController: UIViewController {
var imageForEdit:UIImage?
override func viewDidLoad() {
super.viewDidLoad()
print(imageForEdit ?? "Image was nil")
}
}
Using prepare(for segue: UIStoryboardSegue, sender: Any?) is the preferred way for a Storyboard-based app to pass data between View Controllers. It's very simple and it works.
Sample project is here if you want to see the working code:
https://www.dropbox.com/s/eog01bmha67c5mv/PushImage.zip?dl=0
var imageForEdit: UIImage? {
didSet {
editingImage.image = imageForEdit
}
}
Replace var imageForEdit = UIImage() with var imageForEdit : UIImage?
i test code my self , make sure that imageView have image
#IBOutlet weak var imageView: UIImageView! {
didSet {
imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true
}
}
You can create an public variable so you can pase data from one viewcontroller to another view controller.
class variables
{
static var image = UIImage()
}
the 2 controller:
#IBOutlet weak var anotherviewcontroller: UIImageView!
anotherviewcontroller.image = variables.image
Why the webView is nil in iOS 8 but not in iOS 9?
and how should I use webview in iOS 8?
Here is the code (swift 2.2)
in a viewController class:
#IBOutlet weak var webView: UIWebView!
override func viewDidLoad() {
super.viewDidLoad()
self.webView?.delegate = self // without '?' in iOS 8 crash
// in iOS 9 not crash
// debug code
if let webView = self.webView { // iOS 8 nil
print("\(webView)") // iOS 9 not nil
}
//...
}
Thanks!
class ViewController: UIViewController, UIWebViewDelegate {
#IBOutlet weak var webView: UIWebView!
let url = NSURL(string: "http://google.com")
override func viewDidLoad() {
super.viewDidLoad()
self.webView.delegate = self
let req = NSURLRequest(URL : url!)
self.webView.loadRequest(req)
}
func webViewDidStartLoad(webView: UIWebView) {
print("start loading")
}
func webViewDidFinishLoad(webView: UIWebView) {
print("finish loading")
}
//...
}
like this, this code can run perfectly in iOS8 & iOS9
One solution:
#IBOutlet weak var webViewXib: UIWebView!
var webView: UIWebView!
override func viewDidLoad() {
super.viewDidLoad()
if let _ = self.webViewXib {
self.webView = self.webViewXib
} else {
self.webView = UIWebView()
self.webView.frame = self.view.bounds
self.view.addSubview(self.webView!)
}
self.webView!.delegate = self
// ...
}
The problem is the way how instantiate your View Controller, you are probably instantiating it as:
MyViewController *myViewController = [[MyViewController alloc] init]
With that you will not have the view ready in your viewDidLoad, instead you should try:
MyViewController *myViewController = [[MyViewController alloc] initWithNibName:"MyViewController" bundle:nil]
I have the following 2 controllers listed below. I'm using delegation to try and create a progressWindow which will run code and print it nicely but where the code is arbitrary.
The closures are defined by the class conforming to the protocol (in my case SyncViewController), but I want to change the UI of the progressWindowViewController from SyncViewControllers codeToRun {} closure. How do I do this?
SyncViewController.swift
import UIKit
class SyncViewController: UIViewController, progressWindowDelegate {
var codeToRun = {
//(self as! ProgressWindowViewController).theTextView.text = "changed the text"
print("code to run")
}
var codeToCancel = {print("code to cancel")}
var titleToGive = "Starting Sync..."
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func yesSyncButtonAction(sender: UIButton) {
//Segue to the ProgressWindowViewController...
}
#IBAction func noSyncActionButton(sender: UIButton) {
tabBarController?.selectedIndex = 1 //assume back to inventory section
}
// MARK: - Navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if(segue.identifier == "SyncToProgressSegue"){
let progressWindow = segue.destinationViewController as! ProgressWindowViewController
progressWindow.controllerDelegate = self //sets the delegate so we have reference to this window still.
}
}
}
ProgressWindowViewController.swift
import UIKit
protocol progressWindowDelegate{
var titleToGive : String {get}
var codeToRun : ()->() {get}
var codeToCancel : ()->() {get}
}
class ProgressWindowViewController: UIViewController {
#IBOutlet weak var theTextView: UITextView!
#IBOutlet weak var theProgressBar: UIProgressView!
#IBOutlet weak var navItemLabel: UINavigationItem!
//Sets delegate
var controllerDelegate:progressWindowDelegate!
override func viewDidLoad() {
super.viewDidLoad()
navItemLabel.title! = controllerDelegate.titleToGive
dispatch_async(dispatch_get_main_queue(),{
self.controllerDelegate.codeToRun() //Will run code accordingly.
})
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func cancelNavItemButtonAction(sender: UIBarButtonItem) {
dispatch_async(dispatch_get_main_queue(),{
self.controllerDelegate.codeToCancel()
})
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
An example of how his might be used is downloading thousands of inventory records with images, which would print the inventory details as it grabs them into the progressWindow.
But this progressWindow could also be used for other large/small tasks that need to print particular stuff into the progressWindow textarea (like logging in and therefore coming from a different view controller than sync in my example). The idea is to make it a dynamic class.
Instead of creating a variable, just use a function/method?
override func viewDidLoad() {
super.viewDidLoad()
dispatch_async(dispatch_get_main_queue(),{
self.controllerDelegate?.codeToRun(self)
})
}
.
protocol progressWindowDelegate : class {
var titleToGive : String {get}
func codeToRun(progressWindowViewController:ProgressWindowViewController)
var codeToCancel : ()->() {get}
}
class SyncViewController: UIViewController, progressWindowDelegate {
func codeToRun(progressWindowViewController:ProgressWindowViewController) {
print("code to run")
}
Also make delegate weak and optional:
delegate weak var controllerDelegate:progressWindowDelegate? = nil
I have loaded a webpage to xcode WebView. But only the upper portion of the page is loaded. I can not scroll down to the bottom of the page. Same fact for pdf. Only upper 2 pages can be scrolled. What can i do ?Here is my code.
Thanks in advance.
import UIKit
class ViewController: UIViewController {
#IBOutlet var webView: UIWebView!
override func viewDidLoad() {
super.viewDidLoad()
var URL = NSURL(string: "http://www.archetapp.com")
webView.loadRequest(NSURLRequest(URL: URL!))
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
//for pdf
import UIKit
class ViewController: UIViewController {
#IBOutlet var webViews: UIWebView!
var path = ""
override func viewDidLoad() {
super.viewDidLoad()
path = NSBundle.mainBundle().pathForResource("ibook", ofType: "pdf")!
let url = NSURL.fileURLWithPath(path)
webViews.scalesPageToFit = true
webViews.scrollView.scrollEnabled = true
webViews.userInteractionEnabled = true
self.webViews.loadRequest(NSURLRequest(URL: url!))
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
Try this!
import UIKit
class ViewController: UIViewController, UIWebViewDelegate {
#IBOutlet var webView : UIWebView
override func viewDidLoad() {
super.viewDidLoad()
//load initial
path = NSBundle.mainBundle().pathForResource("ibook", ofType: "pdf")!
let url = NSURL.fileURLWithPath(path)
var req = NSURLRequest(URL : url)
webView.delegate = self // <---
webView.loadRequest(req)
}
func webViewDidStartLoad(webView : UIWebView) {
//UIApplication.sharedApplication().networkActivityIndicatorVisible = true
println("webViewDidStartLoad")
}
func webViewDidFinishLoad(webView : UIWebView) {
//UIApplication.sharedApplication().networkActivityIndicatorVisible = false
webViews.scalesPageToFit = true
webViews.scrollView.scrollEnabled = true
webViews.userInteractionEnabled = true
println("webViewDidFinishLoad")
}
}
I had the same issue just today and at least in my case it was caused by having the "Scale Pages to Fit" option checked in the WebView properties. I'm assuming Carlos' reply regarding the zoom scale fixes it anyways but I didn't need the option enabled in the first place so that was my easy fix.
I'm playing around with Swift to learn it and right now I'm having trouble getting the text from a UISearchBar
Right now my code looks like this:
import UIKit
class SecondViewController: UIViewController {
#IBOutlet var myWebView : UIWebView
#IBOutlet var adressbar: UISearchBar
override func viewDidLoad() {
super.viewDidLoad()
adressbar.showsScopeBar = true
var url = NSURL(string: "http://google.com")
var request = NSURLRequest(URL: url)
myWebView.scalesPageToFit = true
myWebView.loadRequest(request)
}
func searchBarSearchButtonClicked( searchBar: UISearchBar!) {
var url = NSURL(string: adressbar.text)
var request = NSURLRequest(URL: url)
myWebView.scalesPageToFit = true
myWebView.loadRequest(request)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
In viewDidLoad you must set the delegate of the search bar to be receiving searchBarSearchButtonClicked from it:
import UIKit
class SecondViewController: UIViewController, UISearchBarDelegate
{
#IBOutlet var myWebView : UIWebView
#IBOutlet var adressbar: UISearchBar
override func viewDidLoad()
{
super.viewDidLoad()
adressbar.showsScopeBar = true
adressbar.delegate = self
var url = NSURL(string: "http://google.com")
var request = NSURLRequest(URL: url)
myWebView.scalesPageToFit = true
myWebView.loadRequest(request)
}
func searchBarSearchButtonClicked( searchBar: UISearchBar!)
{
var url = NSURL(string: searchBar.text)
var request = NSURLRequest(URL: url)
myWebView.scalesPageToFit = true
myWebView.loadRequest(request)
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
}
}
Simple (non-specific) answer for those arriving here via search:
If your outlet name for your UISearchBar is 'searchBar'...
#IBOutlet weak var searchBar: UISearchBar!
Then the text entered by the user in UISearchBar is called...
searchBar.text
Two common things Swift coders forget:
1. Make sure to add UISearchBarDelegate class...
ViewController: UIViewController, UISearchBarDelegate
Don't forget to identify your view class as the delegate...
Inside viewDidLoad you could write...
searchBar.delegate = self
If you forget #1 above you won't be able to auto-complete the methods you'll need to implement like...
func searchBarSearchButtonClicked(_ seachBar: UISearchBar) { your code }
... which is given to you by the delegate protocol.
1.First thing is to conform to the UISearchbarDelegate.
2.Set the search bar delegate to self.
You can find more on this here Swift iOS tutorial : Implementing search using UISearchBar and UISearchBarDelegate