Detecting when tabBar item is pressed when is page - ios

I have a UITabBar with 4 tabs.
I want to that a specific function will be called in each ViewController of the tab when the tabBarItem is pressed twice (like, the user is now on ProfileVC and presses on Profile item, I want to refresh the view).
How can I detect when the user pressed on the tab that he is in its view now?
Thank you!

One option is do the refreshing inside viewWillAppear() method. And the second one is considerably long.
In parent view controller
protocol ParentDelegate {
func refresh()
}
class LandingViewController: UIViewController, UITabBarDelegate {
var delegate: ParentDelegate?
var selectedItem: UITabBarItem!
override func viewDidLoad() {
super.viewDidLoad()
self.tabBar.delegate = self
self.selectedItem = self.tabBar.selectedItem
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "SegueNameForDestinationViewController1" {
if let vc = segue.destinationViewController as? YourDestinationViewController1 {
self.delegate = vc.self
}
} else if segue.identifier == "SegueNameForDestinationViewController2" {
if let vc = segue.destinationViewController as? YourDestinationViewController2 {
self.delegate = vc.self
}
}
}
func tabBar(tabBar: UITabBar, didSelectItem item: UITabBarItem) {
if self.selectedItem == item {
self.delegate?.refresh()
}
self.selectedItem = item
}
}
In each tab view controller,
class TabViewController: UIViewController, ParentDelegate {
func refresh() {
//write your code here
}
}

Related

Form sheet is not getting detected when being swiped down

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.

Change Label text in a ContainerView on click of a button from other class (Uiviewcontroller)

I got small containerView with UILabel on main app screen. I got UIButton on main UIViewController. I want to change text of label that belongs to containerView class by clicking button in UIViewController.
I try to make it with delegation, but for some reason i got a mistake (Unwraping optional)...
I try to make it with Protocol, bud method "addText" in ContView dont works((((((
class ViewController: UIViewController {
var delegate: DelegateProtocol?
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func button(_ sender: Any) {
delegate?.addText(String2: "123")
}}
///////////////////////////////////////////////////////////////////////
protocol DelegateProtocol {
func addText(String2: String)
}
//////////////////////////////////////////////////////////////////////
class ContViewController: UIViewController, DelegateProtocol {
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "con" {
let vc = segue.destination as! ViewController
vc.delegate = self
}
}
func addText(String2: String) {
label.text = String2
}
#IBOutlet weak var label: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
}
first make an global variable in your view controller
private var viewController: YourVC?
then give your container view segue an identifier and do follwing
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "yourviewcontroller Segue identifiew" { //your container view segue identifier
viewController = segue.destination as? SelectedImageVC
}
}
now you can use you viewController to access label in your containerview controller like
if let controller = viewController {
controller.yourlabel.text = "text you want"
}

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")
}
}

Return array to another ViewController in Swift

I have two UIViewControllers and each one has an UITableView. Lets say that when I call from View-A to View-B, I take the cells which are marked in the UITableView in View-B and, after pressing a button I want to return an array with all the data selected from View-B to View-A, dismiss View-B and represent that information in the TableView of View-A.
How can I pass that array ? How do I have to reaload the data in View-A to show it after dimissing View-B ?
Any idea?
Thank you very much!!
protocol DataPasserDelegate {
func sendDatatoA(dataArrayFromB : Array<AnyObject>)
}
class ViewB: UIViewController {
var delegate: DataPasserDelegate!
var dataArrayB = Array<AnyObject>()
#IBAction func sendData(sender: Any){
self.dismiss(animated: true) {
self.delegate.sendDatatoA(dataArrayFromB: self.dataArrayB)
}
}
}
class ViewA: UIViewController, DataPasserDelegate {
#IBOutlet weak var tableViewA: UITableView!
var dataArrayA = Array<AnyObject>()
//MARK: - DataPasserDelegate
func sendDatatoA(dataArrayFromB: Array<AnyObject>) {
dataArrayA = dataArrayFromB
self.tableViewA.reloadData()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destVC = segue.destination as? ViewB{
destVC.delegate = self
}
}
}
So you can use prepareForSegue:
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
if (segue.identifier == "segueID") {
if let controller = segue.destination as? YourVC{
controller.array = yourArray
controller.tableView.reloadData()
}
}
}
You will need to use delegate for this. For more information on delegates you can go through my blog here.

How do I get my TableView selection to open my modal view?

I created a TableView with a TableViewCell in it.
I would like my cells in my TableView to open up in a separate ViewController.
My storyboard looks like this:
My TableViewController has this:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "ShowVerse" {
let pageDetailViewController = segue.destinationViewController as! PageViewController
// Get the cell that generated this segue.
if let selectedPageCell = sender as? PageTableViewCell {
let indexPath = tableView.indexPathForCell(selectedPageCell)!
let selectedPage = pages[indexPath.row]
pageDetailViewController.page = selectedPage
}
}
}
And in my PageViewController.swift I have this :
var page: Page?
override func viewDidLoad() {
super.viewDidLoad()
if let page = page {
chapter.text = String(page.chapter)
verse.text = String(page.verse)
}
}
I do not get any errors. But tapping the cells does not nothing. What might I be missing?
Try this:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
performSegueWithIdentifier("ShowVerse", sender: self)
}
Swift
code in didSelectRowAtIndexPath
self.performSegueWithIdentifier("homeSegue", sender: self)
Before switching to next view controller, if you wants to pass value to next view controller
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "homeSegue")
{
var homeController = segue.destinationViewController as? ViewController
homeController.name = "valeu"
}
}
Objective-C
code in didSelectRowAtIndexPath
[self performSegueWithIdentifier:#"ShowVerse" sender:self];
Before switching to next view controller, if you wants to pass value to next view controller
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([segue.identifier isEqualToString:#"ShowVerse"]) {
HomeViewController *controller = segue.destinationViewController;
controller.propertyName = #"value";
}
}

Resources