Preload UIWebView - ios

I've tried in my code to preload an UIWebView but without any result.
I can't figure out what is wrong in the code.
First UIViewController
func viewDidLoad(){
let gallery = storyboard?.instantiateViewControllerWithIdentifier("Gallery") as! GalleryViewController
gallery.loadwWebView()
}
In the second UIViewController
func loadwWebView(){
let webView = UIWebView(frame: CGRect(x: 0, y: 0, width: view.bounds.size.width, height: view.bounds.size.height))
webView.loadRequest(NSURLRequest(URL: NSURL(string: "https://www.google.com")!))
self.view.addSubview(webView)
}
I've choose the programmatically to create the UIWebView way because if I use the #IBOutlet its gonna crash.

The problem is that you're instantiating a gallery, which is in turn creating a web view, but gallery is a local variable and will be deallocated when it falls out of scope.
You need to keep a reference to this view controller (e.g. make it a property of the current view controller). If you do this, you need to make sure that when you transition to this view controller, you don't use a segue (because that will create a second instance of that second view controller), but rather programmatically transition to the one you already instantiated.
You might also want to save a reference to that web view you added to the second view controller's view hierarchy because otherwise you won't be able to reference it again (or at least not without some cumbersome enumeration of the subviews).

Related

Picker View uncaught exception SWIFT

Hello I am a beginner at SWIFT and I have an issue with my project : I have a picker View on one of my View controller and I think that I have connected all outlets but when I execute the code and test my app on the emulator it comes an error when I click on the button (on the previous View) that has to open the view in which my picker View is set. When I get rid of my the picker View from the View controller, there is no more error.
The fact is that I have watched every tutorials on PickerView and did all they shew ...
I don't know where comes from my mistake.
I let some screen shots to be clearer
The first problem is that you don't store the created picker view instance. You instantiate it inside of a function, assign the delegate and dataSource and then you don't store it in your class. So the ARC (Automatic Reference Counting) releases it, because it thinks the instance is not longer needed. Just create a variable in your PickerController and store as long as the view controller is alive.
The second problem is that you actually want to see the picker view, so you need to add it to the view controller's view. You might need to position it right or use layout constraints (Search for Auto Layout).
var pickerView: UIPickerView!
func createPickerView() {
pickerView = UIPickerView()
pickerView.delegate = self
pickerView.dataSource = self
view.addSubview(pickerView)
}

Adding An UITableViewController on to a SubView

An UITableViewController pretty much takes up the entire view. I need a way to limit its height, width and add some shadows etc. For a clear explanation, I won't show the UITableViewController's contents.
Without the use of a storyboard, I subviewed the UITableViewController:
// In another UIViewController
let otherController = OtherController() // A subclass of UITableViewController
let otherControllerView = otherController.view
someView.addSubView(otherControllerView)
[...] // bunch of constraints
Notes:
In AppDelegate, if I set the rootController as OtherController(), everything works as it should. If I change it back to SomeView(), I see my modified tableView. If I should click it, it disappears.
This was the only thing that came close to my issue but sadly, I could not understand the answers provided as nothing made any sense to me.
I need to understand, why it disappears when touched etc.
view.bringSubviewToFront(...) proved futile. I'm gessing that a tableView should be rendered in its own controller and not in another view?
So just to answer this question, indeed you got two options. One is the best way, as suggested by Rakesha. Just use UITableView. Add it as a subview. Done.
And in the future, if you really want any controller to be added onto any UIView, remember you need to add that controller as a child. For example, in your case:
The controller of the view that will hold your UITableViewController will add such UITableViewController as a child.
self.addChild(yourUITableViewController)
self.whatEverViewContainer.addSubview(yourUITableViewController.view)
// Take note of the view of your tableViewController above^.
// Then setup the constraints of your yourUITableViewController.view below.
I hope this helps!
You must add the instance of UITableViewController's subclass as child view controller of the other view controller. You need to ensure few points in order to make it work. The points are as listed below:
Create the instance of your TableViewController
Add it as a child view controller of the other view controller
Add its view as a subview of the desired view (you may do these steps in viewDidLaod since they need to be done only once)
Keeping in mind the view cycle of a view controller. You must keep a weak reference of the child view controller aka TableViewController to adjust its view frame after the parent view controller has laid its subviews.
Code here:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let vc = TableViewController()
addChildViewController(vc)
view.addSubview(vc.view)
vc.didMove(toParentViewController: self)
childVC = vc
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
childVC?.view.frame = view.frame
}

View Reloads When Frame is Changed

I have a YouTubePlayer (from here) in my app. I have a UIViewController (we'll call this MainViewController) with a UITableView full of videos. Whenever a user taps on a cell, it opens another UIViewController (we'll call this DetailViewController) with my custom xib view called playerView. Like I said, playerView is a custom xib view and in that view is my YouTubePlayer. This is how I set up playerView in my DetailViewController
playerContainer.addSubview(playerView)
playerView.frame = CGRect(x: 0, y: 0, width: playerContainer.frame.size.width , height: playerContainer.frame.size.height)
playerView.player.loadVideoID(nowPlayingVideo.id)
Ok so this works great. BUT... whenever the user dismisses DetailViewController, I want playerView to be moved to the MainViewController. Like where the user can see what is playing in the background. So to do this, I added this code in DetailViewController...
override func viewWillDisappear(_ animated: Bool) {
nowPlayingView.addSubview(playerView)
playerView.frame = CGRect(x: 8, y: 8, width: width, height: height)
playerView.layoutIfNeeded()
}
nowPlayingView is another custom xib view and is added to the app's window earlier on. So this is where I start running into problems. This code works great. The frame is changed correctly and it's added to nowPlayingView, but, the YouTubePlayer in playerView seems to reload. So it pauses playback, shows a loading icon, and then resumes. It's pretty annoying. This shouldn't be happening because the video is already loaded in the YouTubePlayer. I'm pretty sure it happens only whenver I am changing the frame of playerView. Does anyone have any ideas on how to fix this?
When the video resumes playing after loading, does the video start over or does it resume where it left off before changing the view?

Changing width of child view controller

I added child view controller to parent view controller programmatically in swift 3.0.
But I do not want the child view controller width as full screen, I want to customise the width and height of the child view controller. I tried to open the custom size child view controller, but it is not working.
// Here is my code
let secondViewController = storyboard.instantiateViewController(withIdentifier: storyBoardName)
secondViewController.modalPresentationStyle = UIModalPresentationStyle.custom
secondViewController.view.frame = CGRect(x: 0, y: 0, width: self.view.bounds.width-500, height: self.view.bounds.height)
self.present(secondViewController, animated: false, completion: nil)
Is there a way to achieve this?
In your code, you are not adding the secondViewController as childview controller. You are presenting that view controller. There is a difference.
You are trying to use UIModalPresentationStyle.custom to present viewcontroller using custom style. But using this custom style is not this trivial.
From documentation:
Creating a custom style involves
subclassing UIPresentationController and using its methods to animate
any custom view onto the screen and to set the size and position of
the presented view controller. The presentation controller also
handles any adaptations that occur because of changes to the presented
view controller’s traits
It tells you that you need to subclass UIPresentationController and subclass its method(with other methods) - (CGRect)frameOfPresentedViewInContainerView to set the frame of the presented viewcontroller.
More is explained in this link.
You can ofcourse achieve all this by actually adding a childviewcontroller.
Steps would be like this:
Create your child viewcontroller instance.
Set its view frame to whatever you want.
Add its view as a subview on to parent view controller's view using addSubview:
Call [addChildViewController] on parent viewcontrller (https://developer.apple.com/documentation/uikit/uiviewcontroller/1621394-addchildviewcontroller)
It depends on what you're trying to do, when I want to show some UI on top of another UIViewController I usually use a fullscreen view controller with self.modalPresentationStyle = .overFullScreen. Then I create another view which has the visible size I actually want to show to the user. This allows you to do pretty much anything you want.
But if you want an actual child viewcontroller, you need to use the appropriate functions for it.

Swift : addSubview before StoryBoard

Im not new to swift but new to using storyboard, i typically do everything programmatically but decided to change it up a bit.
I have a storyboard with a bunch of UIButtons(numbers 0 - 9, similar to a calculator) and i would like to add a view on the lowest layer before all the buttons are added. So in terms of layers : UIView -> UIButtons
I thought simply adding the viewDidLoad() and putting the view first would work but it didn't:
override func viewDidLoad() {
blurView = BlurViewEffect(frame: CGRect(x: 0, y: 0, width: self.view.bounds.width, height: self.view.bounds.height))
self.view.addSubview(blurView)
designButtons()
}
Any idea how I can load the storyboard last?
There's no way to load the storyboard before the viewDidLoad method. Storyboards get serialized, so basically they're loaded with the init:coder method.
However, typical layouting tools should do the trick for your needs. Simply use view.sendSubviewToBack(blurView) to make sure your blurView is at the back of the view.

Resources