This func is used for showing/presenting ViewController.
let noteViewController = NoteViewController()
extension NoteTableViewController: UIViewControllerTransitioningDelegate {
func remindLater() {
if let note = notificationNote?.copy() as? Note {
noteViewController.transitioningDelegate = self
noteViewController.modalPresentationStyle = UIModalPresentationStyle.fullScreen
noteViewController.modalTransitionStyle = UIModalTransitionStyle.coverVertical
resultSearchController.searchBar.isHidden = true
present(noteViewController, animated: true, completion: nil)
//show(noteViewController, sender: self)
}
}
}
On the ViewController i am trying to present i've an outlet for UIDatePicker object. On viewdidLoad() method i have this line that causes an error.
frameDatePicker = remindDatePicker.frame
So, i found remindDatePicker and other objects equal to nil.
Where should i find a mistake?
Related
I'm applying for a junior developer position and I've got a very specific task, that already took me 3 days to complete. Sounds easy - pass data to rootViewController.
That's what I've done:
1)
private func userDefaultsToRootController() {
let input = textField.text!
defaults.set(input, forKey: "SavedLabel")
navigationController?.popViewController(animated: true)
}
private func segueToRootViewController() {
let destinationVC = MainScreen1()
let input = textField.text!
if input == "" { self.navigationController?.popToRootViewController(animated: true) }
destinationVC.input = input
navigationController?.pushViewController(destinationVC, animated: true)
}
private func popToNavigationController() {
let input = textField.text!
if let rootVC = navigationController?.viewControllers.first as? MainScreen1 {
rootVC.input = input
}
navigationController?.popToRootViewController(animated: true)
}
I've used CoreData
But here is the difficult part - I've got an email, that all these methods are not good enough and I need to use delegate and closure. I've done delegation and closures before, but when I popToRootViewController delegate method passes nil. Could you at least point where to find info about this?
** ADDED **
There are 2 View Controllers: Initial and Second one.
That's what I have in the Initial View Controller:
var secondVC = MainScreen2()
override func viewDidLoad() {
super.viewDidLoad()
secondVC.delegate = self
}
That's how I push SecondViewController
#objc private func buttonTapped(_ sender: CustomButton) {
let nextViewController = MainScreen2()
navigationController?.pushViewController(nextViewController, animated: true)
}
In SecondViewController I've got this protocol
protocol PassData {
func transferData(text: String)
}
Also a delegate:
var delegate: PassData?
This is how I go back to initial view controller
#objc private func buttonTapped(_ sender: CustomButton) {
if let input = textField.text {
print(input)
self.delegate?.transferData(text: input)
self.navigationController?.popToRootViewController(animated: true)
}
}
Back to the Initial view controller where I've implemented delegate method
extension MainScreen1: PassData {
func transferData(text: String) {
print("delegate called")
label.text = text
}
}
Delegate doesn't get called.
BASED ON YOUR EDIT:
You must set the delegate in buttonTapped
#objc private func buttonTapped(_ sender: CustomButton) {
let nextViewController = MainScreen2()
nextViewController.delegate = self // HERE WHERE YOU SET THE DELEGATE
navigationController?.pushViewController(nextViewController, animated: true)
}
You can delete the second instance and your code in viewDidLoad. That's not the instance you push.
This should point you in the right direction to use delegation and completion handler.
protocol YourDelegateName {
func passData(data:YourDataType)
}
class SecondViewController: UIViewController {
var delegate: YourDelegateName?
func passDataFromSecondViewController(){
YourCoreDataClass.shared.getCoreData { (yourStringsArray) in
self.delegate?.passData(data: yourStringsArray)
self.navigationController?.popToRootViewController(animated: true)
}
}
class InitialViewController: UIViewController, YourDelegateName {
override func viewDidLoad() {
super.viewDidLoad()
// or whenever you instantiate your SecondViewController
let secondViewController = SecondViewController()
secondViewController.delegate = self //VERY IMPORTANT, MANY MISS THIS
self.navigationController?.pushViewController(createVC, animated: true)
}
func passData(data:YourDataType){
//user your data
}
}
class YourCoreDataClass: NSObject {
static let shared = YourCoreDataClass()
func getCoreData (completion: ([String]) -> ()){
........... your code
let yourStringsArray = [String]() // let's use as example an array of strings
//when you got the data your want to pass
completion(yourStringsArray)
}
}
nil Delegate between two ViewController with two different Bundle using swift 4 (commented in second code)
here is my code :
First ViewController :
class FirstVC : UIViewController, MerchantResultObserver{
var secVC = SecondVC()
override func viewDidLoad() {
secVC.delegate = self
let storyboard = UIStoryboard(name: “SecondVC”, bundle: Bundle(identifier: “SecondBundle”))
let controller = storyboard.instantiateInitialViewController()
self.present(controller!, animated: true, completion: nil)
secVC.initSecondVC(data)
}
func Error(data: String) {
print("-------------Error Returned------------- \(data)")
}
func Response(data: String) {
print("-------------Response Returned------------- \(data)")
}
}
Second ViewController :
public class SecondVC: UIViewController {
public weak var delegate: MerchantResultObserver!
public func initSecondVC(_ data : String){
print(data)
}
#IBAction func sendRequest(_ sender: UIButton) {
delegate?.Response(data: “dataReturnedSuccessfully”) // delegate is nil //
dismiss(animated: true, completion: nil) // returned to FirstVC without returning “dataReturnedSuccessfully” //
}
}
public protocol MerchantResultObserver: class{
func Response(data : String)
func Error(data : String)
}
Any help would be appreciated
var secVC = SecondVC()
and
let storyboard = UIStoryboard(name: “SecondVC”, bundle: Bundle(identifier: “SecondBundle”))
let controller = storyboard.instantiateInitialViewController() as? SecondVC
These both are different instances.
You can assign a delegate to the controller, like
controller.delegate = self
It will call the implemented delegate methods in First View Controller.
Full Code.
let storyboard = UIStoryboard(name: “SecondVC”, bundle: Bundle(identifier: “SecondBundle”))
if let controller = storyboard.instantiateInitialViewController() as? SecondVC {
//Assign Delegate
controller.delegate = self
//It's not init, but an assignment only, as per your code.
controller.initSecondVC(data)
self.present(controller, animated: true, completion: nil)
}
One more thing, Don't present View in ViewDidLoad. You can put a code in some button or in a delay method.
I am having issues trying to pass the data back to the ViewController (from BarCodeScannerViewController to TableViewController)
SecondVC (BarCodeScannerViewController.swift):
#objc func SendDataBack(_ button:UIBarButtonItem!) {
if let presenter = self.presentingViewController as? TableViewController {
presenter.BarCode = "Test"
}
self.dismiss(animated: true, completion: nil)
}
FirstVC (TableViewController.swift):
// The result is (BarCode - )
var BarCode: String = ""
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
print("BarCode - \(BarCode)")
}
Each time ViewWillAppear is running the value is not set, what could be causing this issue?
You should use the delegate pattern. I doubt in your code above that self.presentingViewController is actually set.
An example of using the delegate pattern for this:
// BarCodeScannerViewController.swift
protocol BarcodeScanningDelegate {
func didScan(barcode: String)
}
class BarCodeScannerViewController: UIViewController {
delegate: BarcodeScanningDelegate?
#objc func SendDataBack(_ button:UIBarButtonItem!) {
delegate?.didScan(barcode: "Test")
}
}
// TableViewController
#IBAction func scanBarcode() {
let vc = BarCodeScannerViewController()
vc.delegate = self
self.present(vc, animated: true)
}
extension TableViewController: BarcodeScanningDelegate {
func didScan(barcode: String) {
print("[DEBUG] - Barcode scanned: \(barcode)")
}
}
I have a UIWebView and inside that I have to load a url.
Problem is that After opening webView Memory leak is happened.
I mean I am not able to remove memory leak.
Here below is my code :-
import UIKit
import Toast_Swift
class WebViewController: UIViewController,UIWebViewDelegate {
//WebView
#IBOutlet weak var webView: UIWebView!
//URL
var strUrl : String? = nil
//Tag
var tag : Int! = 0
//ViewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
//Delegate of web view
webView.delegate = self
//webView.stringByEvaluatingJavaScript(from: "localStorage.clear();")
self.webView.loadRequest(URLRequest(url: URL(string: self.strUrl!)!))
//Loading View
self.view.makeToastActivity(.center)
}
//MARK :- Web view delegate.
func webViewDidFinishLoad(_ webView: UIWebView) {
//ToastManager.shared.tapToDismissEnabled = true
self.view.hideToastActivity()
}
//Button Back Action
#IBAction func btnBack(_ sender: Any) {
if (tag == 1) {
webView.delegate = nil
self.strUrl = ""
webView.removeCache()
let gotoCreateView = self.storyboard?.instantiateViewController(withIdentifier: "CreateAccountView") as! CreateAccountView
self.present(gotoCreateView, animated: true, completion: nil)
} else {
webView.delegate = nil
self.strUrl = ""
webView.removeCache()
let gotoAboutUsView = self.storyboard?.instantiateViewController(withIdentifier: "AboutUsView") as! AboutUsView
self.present(gotoAboutUsView, animated: true, completion: nil)
}
/*if (1 == tag)
{
webView.delegate = nil
webView.removeCache()
let gotoCreateView = self.storyboard?.instantiateViewController(withIdentifier: "CreateAccountView") as! CreateAccountView
self.present(gotoCreateView, animated: true, completion: nil)
}
else
{
webView.delegate = nil
webView.removeCache()
let gotoAboutUsView = self.storyboard?.instantiateViewController(withIdentifier: "AboutUsView") as! AboutUsView
self.present(gotoAboutUsView, animated: true, completion: nil)
}*/
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
webView.delegate = nil
webView.removeCache()
webView.delegate = self
self.webView.reload()
}
}
extension UIWebView
{
func removeCache()
{
URLCache.shared.removeAllCachedResponses()
URLCache.shared.diskCapacity = 0
URLCache.shared.memoryCapacity = 0
if let cookies = HTTPCookieStorage.shared.cookies {
for cookie in cookies {
HTTPCookieStorage.shared.deleteCookie(cookie)
}
}
}
}
What can I do to remove memory leak?
Thanks
Apart from your code, you need to get these points:
The first thing is try to not add the webView in main view, instead of this you can set alpha or hidden property. If you are using hidden property, then on unhiding make their delegate set to nil and try to manage that WebView will not work in background when it is hidden.
If you are showing in new ViewController, then when we are pushing the WebView, set their delegate and reload the request. Now when you are trying to back from that view. Before poping, set their delegate to nil, set nil to all the local variables that are used in it.
For Example:
On ViewDidLoad: you are setting delegate,
Now when you pop, means move to previous screen use these lines of code:
webView.delegate = nil
webView.removeCache()
And,
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
webView.delegate = nil
webView.removeCache()
webView.delegate = self
self.webView.reload()
}
}
And on Back button:
#IBAction func btnBack(_ sender: Any) {
if (tag == 1) {
webView.delegate = nil
self.strUrl = ""
webView.removeCache()
let gotoCreateView = self.storyboard?.instantiateViewController(withIdentifier: "CreateAccountView") as! CreateAccountView
self.present(gotoCreateView, animated: true, completion: nil)
} else {
webView.delegate = nil
self.strUrl = ""
webView.removeCache()
let gotoAboutUsView = self.storyboard?.instantiateViewController(withIdentifier: "AboutUsView") as! AboutUsView
self.present(gotoAboutUsView, animated: true, completion: nil)
}
}
I have two View Controllers: "DiscoverViewController" and "LocationRequestModalViewController".
The first time a user opens the "DiscoverViewController", I overlay "LocationRequestModalViewController" which contains a little blurb about accessing the users location data and how it can help them.
On the "LocationRequestModalViewController" there are two buttons: "No thanks" and "Use location". I need to send the response from the user back to the "DiscoverViewController"
I have done some research and found that delegates/protocols are the best way to do it, so I followed a guide to get that working, but I'm left with 2 errors and can't figure them out.
The errors are:
On DiscoverViewController
'DiscoverViewController' is not convertible to 'LocationRequestModalViewController'
On LocationRequestModalViewController
'LocationRequestModalViewController' does not have a member name 'sendBackUserLocationDataChoice'
I've marked where the errors are happen in the following files:
DiscoverViewController.swift
class DiscoverViewController: UIViewController, UITextFieldDelegate, CLLocationManagerDelegate, LocationRequestModalViewControllerDelegate {
func showLocationRequestModal() {
var storyboard = UIStoryboard(name: "Main", bundle: nil)
var locationRequestVC: AnyObject! = storyboard.instantiateViewControllerWithIdentifier("locationRequestVC")
self.presentingViewController?.modalPresentationStyle = UIModalPresentationStyle.CurrentContext
self.tabBarController?.presentViewController(locationRequestVC as UIViewController, animated: true, completion: nil)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
let vc = segue.destinationViewController as LocationRequestModalViewController
vc.delegate = self //This is where error 1 happens
}
func sendBackUserLocationDataChoice(controller: LocationRequestModalViewController, useData: Bool) {
var enableData = useData
controller.navigationController?.popViewControllerAnimated(true)
}
override func viewDidLoad() {
super.viewDidLoad()
showLocationRequestModal()
}
}
LocationRequestModalViewController
protocol LocationRequestModalViewControllerDelegate {
func sendBackUserLocationDataChoice(controller:LocationRequestModalViewController,useData:Bool)
}
class LocationRequestModalViewController: UIViewController {
var delegate:LocationRequestModalViewController? = nil
#IBAction func dontUseLocationData(sender: AnyObject) {
self.dismissViewControllerAnimated(true, completion: nil)
}
#IBAction func useLocationData(sender: AnyObject) {
delegate?.sendBackUserLocationDataChoice(self, useData: true) // This is where error #2 happens
}
override func viewDidLoad() {
super.viewDidLoad()
//Modal appearance stuff here...
}
}
The answer is in your question itself. Both errors tells the exact reason.
Issue 1
let vc = segue.destinationViewController as LocationRequestModalViewController
vc.delegate = self //This is where error 1 happens
The self is of type DiscoverViewController
But you declared the delegate as:
var delegate:LocationRequestModalViewController? = nil
You need to change that to:
var delegate:DiscoverViewController? = nil
Issue 2
The same reason, LocationRequestModalViewController does not confirm to the LocationRequestModalViewControllerDelegate, change the delegate declaration.
You have defined your delegate as having type LocationRequestModalViewController which does not conform to LocationRequestModalViewControllerDelegate.