Form sheet is not getting detected when being swiped down - ios

I have a parent view controller and a child view controller. I have a button that can show that child view controller. The button does these actions: self.performSegue(withIdentifier: "showComments", sender: self). I also have prepared the segue and set segue.destination.presentationController?.delegate = self. I have put UIAdaptivePresentationControllerDelegate into my view controller and tried putting this function:
public func presentationControllerDidDismiss(
_ presentationController: UIPresentationController)
{
print("dismissed")
}
When I try to drag down the form sheet it doesn't print anything telling me that something is wrong here. Is there a reason to why this is happening?
Edit: Here is my view controller:
import UIKit
class ViewController: UIViewController, UIAdaptivePresentationControllerDelegate {
func presentationControllerWillDismiss(_: UIPresentationController) {
print("yep2")
viewWillAppear(true)
}
#IBOutlet weak var commentImage: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
let vc = CommentingViewController()
vc.presentationController?.delegate = self
let tappp = UITapGestureRecognizer(target: self, action:#selector(ChannelVideoViewController.tapppFunction))
commentImage.addGestureRecognizer(tappp)
// Do any additional setup after loading the view.
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
if segue.destination is CommentingViewController {
if segue.identifier == "showComments" {
segue.destination.presentationController?.delegate = self
}
}
}
var isDismissed: Bool = true
#objc func tapppFunction(sender:UITapGestureRecognizer) {
isDismissed = true
self.performSegue(withIdentifier: "showComments", sender: self)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(true)
isDismissed = true
print("View Disappeared")
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
isDismissed = false
print("view appeared")
}
}
Edit 2: I'm not sure if this helps but I also have my child view controller in another storyboard.

Your issue is occurring probably because of the delegate is not getting set. Modify the prepare(for:,sender:) method to the following:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destination = segue.destination as? CommentingViewController {
destination.presentationController?.delegate = self
} else {
print("Not CommentingViewController")
segue.destination.presentationController?.delegate = self
}
}

In my original question I actually put a modified version of my view controller as it was pretty big and messy with other things. After looking at my prepare(for:,sender:) I realized that I was checking for the wrong view controller (Frakenstein kind of helped me find it). Here is what I'm talking about:
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
if segue.destination is OtherViewController
{
if let vc = segue.destination as? OtherViewController {
if segue.identifier == "showOther" {
vc.other = self.other
}
} else if segue.destination is CommentingViewController {
if segue.identifier == "showComments" {
segue.destination.presentationController?.delegate = self
}
}
}
}
So it wasn't working too well. But it does work through storyboard references.

Related

I'm trying to use a protocol and delegate pattern which will pass the data in my array back to the parent view controller

I am new to Xcode and am trying to save an array from secondViewController into the View controller. I have a a series of view controllers embedded in a navigation controller so when I click 'back' on the navigation bar I want to keep the data that was collected in an array 'collectionArray' and save to 'collectionArray2' . Here is the protocol delegate method I've tried:
This is in my ViewController where I want the array saved to :
import UIKit
class ViewController: UIViewController {
var collectionArray2: [String] = []
override func viewDidLoad() {
super.viewDidLoad()
let controller = secondViewController()
controller.delegate = self
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let first = segue.destination as! secondViewController
first.collectionArray.append(contentsOf: collectionArray2)
}
}
extension ViewController: PopupDelegate {
func popupSelectedView(array: [String]) {
collectionArray2.append(contentsOf: array)
}
}
This is my secondViewController where I want to take 'collectionArray':
import UIKit
protocol PopupDelegate: class{
func popupSelectedView(array: [String])
}
class secondViewController: UIViewController {
var exerciseButton: String!
var collectionArray: [String] = []
weak var delegate: PopupDelegate?
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func Exercisess(_ sender: UIButton){
exerciseButton = sender.currentTitle
collectionArray.append(exerciseButton!)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if self.isMovingFromParent {
delegate?.popupSelectedView(array: collectionArray)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let second = segue.destination as! FinalViewController
second.cellLabelArray.append(contentsOf: collectionArray)
}
}
Thank you
your problem is that your are referring to a difference instance of secondViewController. Don't set your delegate in viewDidLoad but when you prepare the segue:
override func viewDidLoad() {
super.viewDidLoad()
//let controller = secondViewController() REMOVE THIS
//controller.delegate = self REMOVE THIS
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let first = segue.destination as! secondViewController
first.collectionArray.append(contentsOf: collectionArray2)
first.delegate = self // set the delate here
}
}
by the way, you should name all your classes starting with capital letters, so it should be SecondViewController

Calling method in another view controller from modal view controller using a delegate

I am using a modal segue to create a view controller that I want to dismiss and then call a method in the origin view controller. I have used a protocol/delegate pattern but for some reason the method is never called. The code is below: Please note that I removed a lot of non-relevant code to keep it clean here
Thanks!!
VC1:
final class WorkoutViewController: UIViewController, StartWorkoutButtonDelegate {
weak var dataSource: WorkoutViewControllerDataSource!
private var workout: Workout!
private var workoutDataViewController: WorkoutDataViewController?
private var workoutFinishViewController: WorkoutFinishViewController?
private let workoutFinishViewControllerSegueIdentifier = "Workout Finish View Controller Segue"
#IBOutlet private var primaryActionButton: UIButton!
#IBOutlet private var pageControl: UIPageControl!
// MARK: - Handling View Lifecycle
override func viewDidLoad() {
super .viewDidLoad()
let workoutType = dataSource.workoutType(for: self)
workout = Workout(workoutType: workoutType, managedObjectContext: persistentContainer.viewContext)
setPrimaryActionButtonLabel()
}
// MARK: - Handling Storyboard Segues
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
super.prepare(for: segue, sender: sender)
if let destinationWorkoutFinishViewController = segue.destination as? WorkoutFinishViewController {
workoutFinishViewController = destinationWorkoutFinishViewController
}
}
// MARK: - Managing Start and Pause
#IBAction func startOrPauseWorkout() {
if workout.isPaused {
startWorkout()
} else {
pauseWorkout()
}
}
}
VC 2:
protocol StartWorkoutButtonDelegate: AnyObject {
func startOrPauseWorkout()
}
class WorkoutFinishViewController: UIViewController {
weak var delegate: StartWorkoutButtonDelegate?
#IBAction func startWorkout() {
self.delegate?.startOrPauseWorkout()
self.dismiss(animated: true, completion: nil)
}
#IBAction func finishWorkout() {
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
Here set the delegate
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
super.prepare(for: segue, sender: sender)
if let destinationWorkoutFinishViewController = segue.destination as? WorkoutFinishViewController {
destinationWorkoutFinishViewController.delegate = self
}
}

How can I use one var or let from a view controller to another view controller

I made a popup view controller but now I'm trying to pass the data from the popup to the view controller via prepare function. Let's take a look.
// this is from the pop up view controller
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let toBeMoved :ViewController = segue.destination as! ViewController
toBeMoved.enterVC()
amountEntered.text = "\(runningNumber1)"
}
// and I added a func in my main VC but I can't get the var in the VC
// totalCash is a label to be changed when the amount is entered from the
// pop up vc
func enterVC () {
totalCash.text = "\(amountEntered)"
}
I added enterVC to viewDidLoad.
Try this and see:
class TestVC: UIViewController {
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let toBeMoved :ViewController = segue.destination as! ViewController
toBeMoved.amountEntered = runningNumber1
toBeMoved.enterVC()
}
}
class ViewController: UIViewController {
var amountEntered: Int = 0
func enterVC () {
totalCash.text = "\(amountEntered)"
}
}
or try this also.
class TestVC: UIViewController {
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let toBeMoved :ViewController = segue.destination as! ViewController
toBeMoved.enterVC(amountEntered: runningNumber1)
}
}
class ViewController: UIViewController {
func enterVC (amountEntered: Int) {
totalCash.text = "\(amountEntered)"
}
}
//Turns out I needed to put a guard let in order to make this work also added IBAction in the original view controller like so:
class ViewController : UIViewController {
#IBAction func didUnwindSegue (sender: UIStoryboardSegue){
guard let realVC = sender.source as? ViewController else {
return
}
}
}
class TestVC : UIViewController {
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard let realVC = segue.destination as? ViewController else {
return
}
realVC.totalCash.text = runningNumber1
}
}

iOS Swift, with one common method in protocol and two implementations in two ViewControllers, how to decide which ViewControllers method is invoked?

I have a protocol
protocol HandleEmbedController: class {
func printMsg()
}
and 2 container views and 2 corresponding ViewControllers
class EnemyBaseVC: UIViewController, HandleEmbedController {
override func viewDidLoad() {
super.viewDidLoad()
}
var value1 = ""
func printMsg(){
print("printing some embedded message")
}
}
and
class EnemyBase2VC: UIViewController, HandleEmbedController {
func printMsg() {
print("enemy base 2 message")
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
and both use the protocol HandleEmbedController and implement printMsg function.
In the main ViewController I have
class HomeBaseVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
var handleEmbedController:HandleEmbedController?
#IBAction func onclick(_ sender: UIButton) {
handleEmbedController?.printMsg()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "embedseg"){
if let embed = segue.destination as? EnemyBaseVC {
self.handleEmbedController = embed
}
}
if (segue.identifier == "embedseg2"){
if let embed = segue.destination as? EnemyBase2VC {
self.handleEmbedController = embed
}
}
}
}
When button is clicked always EnemyBaseVC method is invoked and prints
printing some embedded message
Is there any way to decide which method is to be invoked?
UPDATE
If you have two container views, both segues will be triggered on load, and handleEmbedController will reference the one ViewController that is loaded last.
If you have some logic to decide which one should be referenced, then you can use it to decide which ViewController will be referenced, like so:
class HomeBaseVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
var handleEmbedController:HandleEmbedController?
// comes from your decision logic
var decisionMaker: Bool = false
#IBAction func onclick(_ sender: UIButton) {
handleEmbedController?.printMsg()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "embedseg"),
let embed = segue.destination as? EnemyBaseVC,
decisionMaker {
self.handleEmbedController = embed
}
else if (segue.identifier == "embedseg2"),
let embed = segue.destination as? EnemyBase2VC,
!decisionMaker {
self.handleEmbedController = embed
}
}
}
be aware that this will set the handleEmbedController on load, if you need more complex behavior, you might as well handle the assignment of handleEmbedController elsewhere than in the segue.
Since this is a scenario where your base ViewController must communicate with more than one object, you can also use notifications instead of delegations. This way, you can decide which message to send when user taps the button. Your base ViewController would look something like this
class HomeBaseVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
// comes from your decision logic
var decisionMaker: Bool = true
#IBAction func onclick(_ sender: UIButton) {
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "BUTTON_WAS_TAPPED"), object: nil, userInfo: ["decision" : decisionMaker])
}
}
while the enemy ViewControllers would look like this (the second one would be the same except the decision value to handle)
class EnemyBaseVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: "BUTTON_WAS_TAPPED"),
object: nil,
queue: nil) { notification in
if let userInfo = notification.userInfo,
let decision = userInfo["decision"] as? Bool,
decision {
self.printMsg()
}
}
}
var value1 = ""
private func printMsg(){
print("printing some embedded message")
}
}

Swift 1.2 - prepareForSegue targeting a View Controller embedded Navigation Controller

As in this question, I need to pass a value from a ViewController to another one, the second VC is embedded in navigation controller. I tried the answer to that question but value printed in console is always nil. Can't figure out what to do.
In First VC I have:
var dataToSend : String!
override func viewDidLoad() {
super.viewDidLoad()
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "toSecondVCSegue" {
println("prepareForSegue occurred test value is: *\(dataToSend)*")
let destinationNavigationController = segue.destinationViewController as! UINavigationController
let targetController = destinationNavigationController.topViewController as! SecondViewController
targetController.receivedTest = dataToSend
}
}
#IBAction func toSecondVCButtonTapped(sender: UIButton) {
performSegueWithIdentifier("toSecondVCSegue", sender: nil)
dataToSend = "passed"
}
in the second I have:
var receivedTest : String!
override func viewDidLoad() {
super.viewDidLoad()
println("in SecondViewController in viewDidLoad receivedTest is: *\(receivedTest)*")
}
override func viewWillAppear(animated: Bool) {
println("in SecondViewController in viewWillAppear receivedTest is: *\(receivedTest)*")
}
override func viewDidAppear(animated: Bool) {
println("in SecondViewController in viewDidAppear receivedTest is: *\(receivedTest)*")
}
I think, the reason is you set value to dataToSend variable after calling performSegueWithIdentifier and so it stays always nil
Try changing your code as :
#IBAction func toSecondVCButtonTapped(sender: UIButton) {
dataToSend = "passed"
performSegueWithIdentifier("toSecondVCSegue", sender: nil)
}
This may help!

Resources