Swift Delegate not being called to close a UIViewController - ios

I have a CenterViewController which contains a Game Controller. I want to add/remove a RulesViewController that the user can easily refer to as they play.
The RulesViewController appears and is dismissed fine. But the delegate.continueGame method is never called. I've added the protocol to RulesViewController. I've added a class extension to CenterViewController to handle the delegate. What am I missing?? Any help much appreciated...
Class CenterViewController: UIViewController {
private var controller: GameController
required init(coder aDecoder: NSCoder){
controller = GameController()
}
override func viewDidLoad() {
// add all the views here
let gameView = UIView(frame: CGRectMake(0,0, ScreenWidth, ScreenHeight))
self.view.addSubview(gameView)
controller.gameView = gameView
}
// method called when rules button on the gameView is pressed
func showRulesForLevel () {
let rulesViewController = storyboard!.instantiateViewControllerWithIdentifier("RulesViewController") as! RulesViewController
presentViewController(rulesViewController, animated: true, completion: nil)
// extension to the Class to handle the delegate
extension CenterViewController: RulesViewControllerDelegate {
//func to continue the game
func continueGame() {
controller.gameView.userInteractionEnabled = true
}
}
In the RulesViewController I have:
protocol RulesViewControllerDelegate {
func continueGame()
}
class RulesViewController: UIViewController {
var delegate: RulesViewControllerDelegate?
override func viewDidLoad() {
super.viewDidLoad()
// code to add a continue button which when pressed calls continueGameAction method
}
func continueGameAction() {
// dismiss the UIViewController so game can continue
self.dismissViewControllerAnimated(true, completion: nil)
// continue the game in CenterViewController
delegate?.continueGame()
}
}
BUT delegate?.continueGame() is never called.

Ok so you need to set the delegate in showRulesForLevel method like this:
rulesViewController.delegate = self
:)

Related

Function not getting called with protocol delegate and view controller swift

I needed to delegate an click action for my UIView class to my UIViewController class since swift does not support multiple class inheritance. So i wanted it such that once a button is clicked on my subview, a function in my ViewController class is called. Am using protocol delegate to achieve this but on the click of my button it does not work for me as the function does not get called. Please help me out. Code snippet would be largely appreciated.
ViewController
var categoryItem: CategoryItem! = CategoryItem() //Category Item
private func setupExplore() {
//assign delegate of category item to controller
self.categoryItem.delegate = self
}
//function to be called
extension BrowseViewController: ExploreDelegate {
func categoryClicked(category: ProductCategory) {
print("clicked")
let categoryView = ProductByCategoryView()
categoryView.category = category
categoryView.modalPresentationStyle = .overCurrentContext
self.navigationController?.pushViewController(categoryView, animated: true)
}
}
Explore.swift (subview)
import UIKit
protocol ExploreDelegate:UIViewController {
func categoryClicked(category: ProductCategory)
}
class Explore: UIView {
var delegate: ExploreDelegate?
class CategoryItem: UIView {
var delegate: ExploreDelegate?
var category: ProductCategory? {
didSet {
self.configure()
}
}
var tapped: ((_ category: ProductCategory?) -> Void)?
func configure() {
self.layer.cornerRadius = 6
self.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.categoryTapped)))
self.layoutIfNeeded()
}
#objc func categoryTapped(_ sender: UIGestureRecognizer) {
delegate?.categoryClicked(category: ProductCategory.everything)
self.tapped?(self.category)
}
}

i want to triger navigationcontroller when i press button in UIView class

I want to trigger Navigation controller to some other screen when i press the button in UIView class. How can i do this?
//Code for UIView Class in Which Button Iboutlet is created
import UIKit
protocol ButtonDelegate: class {
func buttonTapped()
}
class SlidesVC: UIView {
var delegate: ButtonDelegate?
#IBAction func onClickFinish(_ sender: UIButton) {
delegate?.buttonTapped()
}
#IBOutlet weak var imgProfile: UIImageView!
}
//ViewController Class code in Which Button Protocol will be entertained
class SwipingMenuVC: BaseVC, UIScrollViewDelegate {
var slidesVC = SlidesVC()
override func viewDidLoad() {
super.viewDidLoad()
slidesVC = SlidesVC()
// add as subview, setup constraints etc
slidesVC.delegate = self
}
extension BaseVC: ButtonDelegate {
func buttonTapped() {
self.navigationController?.pushViewController(SettingsVC.settingsVC(),
animated: true)
}
}
A more easy way is to use typealias. You have to write code in 2 places. 1. your viewClass and 2. in your View Controller.
in your SlidesView class add a typealias and define param type if you need otherwise leave it empty.
class SlidesView: UIView {
typealias OnTapInviteContact = () -> Void
var onTapinviteContact: OnTapInviteContact?
#IBAction func buttonWasTapped(_ sender: UIButton) {
if self.onTapinviteContact != nil {
self.onTapinviteContact()
}
}
}
class SwipingMenuVC: BaseVC, UIScrollViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
let slidesView = SlidesView()
slidesView.onTapinviteContact = { () in
// do whatever you want to do on button tap
}
}
You can use the delegate pattern to tell the containing ViewController that the button was pressed and let it handle whatever is needed to do next, The view doesn't really need to know what happens.
A basic example:
protocol ButtonDelegate: class {
func buttonTapped()
}
class SomeView: UIView {
var delegate: ButtonDelegate?
#IBAction func buttonWasTapped(_ sender: UIButton) {
delegate?.buttonTapped()
}
}
class ViewController: UIViewController {
var someView: SomeView
override func viewDidLoad() {
someView = SomeView()
// add as subview, setup constraints etc
someView.delegate = self
}
}
extension ViewController: ButtonDelegate {
func buttonTapped() {
self.showSomeOtherViewController()
// or
let vc = NewViewController()
present(vc, animated: true)
}
}

Delegate not executing after call swift

I have a viewController with another containerView insider set up to appear temporarily (added programmatically). The containerView is a sort of operation bar, which allows you to change values of the viewController. The protocol called from an IBAction of a button however, does not call the protocol set up inside the viewController class.
Here is the code from both classes:
class viewController: UIViewController, updateListDelegate {
let dataSource = containerView()
override func viewDidLoad() {
super.viewDidLoad()
dataSource.delegate = self
}
func updateList(sender: containerView) {
print("is called") //is not printed
}
}
The code from the containerView:
protocol updateListDelegate {
func updateList(containerView)
}
class containerView: UIViewController {
var delegate: updateListDelegate?
#IBAction func AddSong(_ sender: UIButton) {
self.delegate?.updateList(sender: self)
}
}
If this method is only to be called from one object, then, in my opinion, I would not define a protocol. If multiple objects are to call this method, then I would define a protocol. This is typically how you would call a method backwards, using a basic delegate.
class ViewController: UIViewController {
let container = ContainerView()
override func viewDidLoad() {
super.viewDidLoad()
container.viewControllerDelegate = self
// push to this instance of container at some point
}
func doSomething() {
print("great success")
}
}
class ContainerView: UIViewController {
weak var viewControllerDelegate: ViewController?
#objc func someAction() {
if let viewControllerDelegate = viewControllerDelegate {
viewControllerDelegate.doSomething()
}
}
}
// prints "great success" when someAction() called
One of the most common mistakes people make is not keeping track of instances. For delegates to work, you must be sure you are using the specific instances that you've instantiated and assigned those delegates to.

Access viewcontroller from button

I have ButtonClass which has buttonTapped method implemented.
The button itself is on the view. I need to add an extra layer when the button is pressed but I don't have access to self in the ButtonClass because self is a button not the view... Basically I need to access self.view found in the viewController but that's another class. If I create an new instance like so viewController() it won't help because it wont' be the same instance.
If you're adding the buttonTapped method from the custom button class then you need to create a delegate, and call the delegate method when the user the buttonTapped method is called.
In your custom button class
protocol YourCustomButtonDelegate {
func changeSomethingInTheView()
}
class YourCustomButtonClass {
var delegate: YourCustomButtonDelegate?
func buttonTapped(_ sender: AnyObject) {
if let delegate = delegate {
delegate.changeSomethingInTheView()
}
}
}
And in the ViewController
class ViewController: UIViewController, CustomCellDelegate {
#IBOutlet weak var button: YourCustomButton!
override func viewDidLoad() {
super.viewDidLoad()
button.delegate = self
}
func changeSomethingInTheView() {
// write your code here...
}
}

Changing the layout of an AlertController

I have used the following code to try and change the layout of a UIAlertController using a nib however the dialog just shows up and looks the same each time regardless of the nib specified, it looks like a translucent grey box, at the bottom of my screen.
class AlertDialogViewController: UIViewController {
var message: String = ""
override init() {
super.init(nibName: "SignUpViewController", bundle: nil)
//Below two lines are important for custom transitions.
transitioningDelegate = self
modalPresentationStyle = .Custom
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
//Other code for your dialog controller
// .
// .
// .
}
extension AlertDialogViewController : UIViewControllerAnimatedTransitioning {
func transitionDuration(transitionContext: UIViewControllerContextTransitioning) -> NSTimeInterval {
return 0.5 //Add your own duration here
}
func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
//Add presentation and dismiss animation transition here.
}
}
extension AlertDialogViewController : UIViewControllerTransitioningDelegate {
func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return self
}
func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return self
}
}
extension UIViewController {
func showAleartWithMessage(message: String) {
var ad = AlertDialogViewController()
ad.message = message
presentViewController(ad, animated: true, completion: nil)
}
}
You can't
The UIAlertController class is intended to be used as-is and does not
support subclassing. The view hierarchy for this class is private and
must not be modified.
Edit: Relevant code to what I said in comment is added
Imagine you want a dialog box with a UILable and two UIButtons instance
class CustomView : UIView {
var commentLabel: UILable!
var okayButton: UIButton!
var cancelButton: UIButton!
init(frame: CGRect) {
super.init(frame: frame)
commentLabel = UILabel()
okayButton = UIButton.buttonWithType(.Custom)
cancelButton = UIButton.buttonWithType(.Custom)
// TODO: Configuration such target, action, titleLable, etc. left to the user
[commentLabel, okayButton, cancelButton].map { self.addSubview($0) }
}
#IBAction func okayButtonAction(sender: AnyObject) {
// TODO: Complete implementation
}
#IBAction func okayButtonAction(sender: AnyObject) {
// TODO: Complete implementation
}
}
class CustomAlertDialogViewCongroller : UIViewController {
override func loadView() {
self.view = CustomView(frame: CGRect(x: 0, y: 0, width: 200, height: 100))
}
}
// In the view controller that you want to present that alert dialog. Let's call it viewController
let customAlertDialogViewController = CustomAlertDialogViewCongroller()
customAlertDialogViewController.modalPresentationStyle = .UIModalPresentationFormSheet
customAlertDialogViewController.modalTransitionStyle = .CoverVertical
viewController.presentViewController(customAlertDialogViewController, animated: true, completion: nil)

Resources