How can i identify self.editButtonItem button's clicked event? - iphone

I set my left bar button of UINavigationController as edit button using the code
leftBarButton = self.editButtonItem;
I want to change some disable/enable properties of other buttons with respect to the edit button's click action.
How can i find whether the Edit button is pressed or not?

The edit button's action sends your view controller the setEditing:animated message. Override this in your subclass to perform other actions when entering or leaving edit mode.
Be sure to call the super implementation at the end to manage the rest of the transition to editing view.

So finally i got the solution...
-(void)setEditing:(BOOL)editing animated:(BOOL)animated {
[super setEditing:editing animated:animated];
if(editing) {
//Do something for edit mode
}
else {
//Do something for non-edit mode
}
}
This method will be called with out changing the original behavior of self.editButtonItem button.

In Swift:
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
....
self.navigationItem.leftBarButtonItem = self.editButtonItem()
}
override func setEditing(editing: Bool, animated: Bool) {
// Toggles the edit button state
super.setEditing(editing, animated: animated)
// Toggles the actual editing actions appearing on a table view
tableView.setEditing(editing, animated: true)
}

In Swift you can follow the below methods:
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.rightBarButtonItem = editButtonItem()
}
override func setEditing(editing: Bool, animated: Bool){
super.setEditing(editing, animated: animated)
tableView.setEditing(editing, animated: true)
}

UIBarButtonItem *barBut=[[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemEdit target:self action:#selector(doSomething)];
self.navigationItem.leftBarButtonItem=barBut;
[barBut release];
.h
-(void)doSomething;
.m
-(void)doSomething{
NSLog(#"dooooooooooooo");
//ur stuff
}
updated:
- (void)setEditing:(BOOL)editing animated:(BOOL)animated
will be called
editButtonItem
Returns a bar button item that toggles its title and associated state between Edit and Done.
- (UIBarButtonItem *)editButtonItem
Discussion
If one of the custom views of the navigationItem property is set to the returned object, the associated navigation bar displays an Edit button if editing is NO and a Done button if editing is YES. The default button action invokes the setEditing:animated: method.
Availability
Available in iOS 2.0 and later.
See Also
#property editing
– setEditing:animated:
Declared In
UIViewController.h
http://developer.apple.com/library/ios/#DOCUMENTATION/UIKit/Reference/UIViewController_Class/Reference/Reference.html

Related

self.tabBarController.selectedIndex not calling viewDidAppear

I've been looking at and trying all the solutions others have posted to this problem, but I'm still not getting it.
My use case is very simple. I have a viewController with a button, when that button is pressed I want to navigate to another tab and reload the data including an api call.
When using the button, I navigate to the tab fine, but viewDidAppear is not being called.
If on another tab, and navigate using the tab bar, viewDidAppear works fine. Also viewWillAppear is working, but I have to add a manual delay to the functions I want to call so it's not ideal.
So what do I need to do to navigate using self.tabBarController.selectedIndex = 0 and get the functionality of viewDidAppear?
Update: The viewWillAppear method I added gets called but I have to add a delay to my functions in order for them to work, and it's a bit clunky, not ideal. Not sure why viewDidAppear will not work :(
Here is a screenshot of the structure:
I appreciate any help on this one!
The "current" ViewController is my tab index 2:
import UIKit
class PostPreviewVC: UIViewController {
//Here I create a post object and post it to the timeline with the below button
#IBAction func postButtonPressed(_ sender: Any) {
//create the post via Firebase api
self.tabBarController?.selectedIndex = 0
}
}
In my destination viewController:
import UIKit
import Firebase
import SDWebImage
import AVFoundation
class HomeVC: UIViewController {
// MARK: - PROPERTIES
var posts = [Post]()
let refreshControl = UIRefreshControl()
//more properties...
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
setupUI()
configureTableView()
reloadTimeline()
UserFirebase.timeline { (posts) in
self.posts = posts
self.tableView.reloadData()
}
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
print("viewDidAppear")
_ = self.view
setupUI()
configureTableView()
reloadTimeline()
UserFirebase.timeline { (posts) in
self.posts = posts
self.tableView.reloadData()
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewDidAppear(animated)
print("viewWillAppear")
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
self.reloadTimeline()
self.configureTableView()
}
}
//All the tableview code below here...
}
Added a custom class for my tab bar controller:
import UIKit
class TabBarController: UITabBarController, UITabBarControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
print("viewDidAppear in tabBar custom Class called")
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
print("viewWillAppear in tabBar custom Class called")
}
}
When you are using UITabBarController, the method viewDidLoad will called only once when any UIViewController is loaded in memory. After that, when you are navigating the same UIViewController, then it will load from memory.
In order to overcome this problem, you must divide your code in viewDidLoad & viewDidAppear. So, in viewDidLoad, you only put that code which you want to intialize once throughout the app such as adding UIView's or other things, while in viewDidAppear / viewWillAppear, you can make API calls or some functions which fetches dynamic data.
Finally, when you are calling self.tabBarController.selectedIndex = 0, it will call viewDidLoad only once and viewDidAppear / viewWillAppear every time when you are navigating that UIViewController.
Hope this helps to understand like how UITabBarController works.
For UITabBarController viewDidLoad only gets called once. and your viewWillAppear and viewDidAppear get called multiple times. you can either check if your viewWillAppear gets called or not. because your view will appear gets called before your viewDidAppear it's just like going through the reverse engineering process.
You can also add viewDidAppear method into your UITabBarController custom class. and call its superclass method into it in that way I think it will solve your problem.
Note: In the case of UITabbarController, Always do your UI update task and API calling a task in either
viewWillAppear or viewDidAppear

Protocol doesn't get read in swift xcode project

i have a UITableview that has unique cells,
each cell has it's own class and they have actions that i want to connect to my main UITableviewcontroller
I attach a protocol and open it in the tableviewcontroller
but it doesn't get read
how could I initialise it or what am I doing wrong ?
here is my cell class :
import UIKit
class AddFaxHeadlineTableViewCell: UITableViewCell {
var delegate: AddFaxHeadlineProtocol?
#IBOutlet weak var addButton: UIButton!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
#IBAction func onAddFaxNumberPressed(_ sender: Any) {
delegate?.faxButtonPressed()
}
}
protocol AddFaxHeadlineProtocol{
func faxButtonPressed()
}
and in my tableviewcontroller I extend the protocol:
class SummaryMainTableViewController: UITableViewController, AddFaxHeadlineProtocol, AddEmailHeadlineProtocol {
but the function itself never gets read:
func faxButtonPressed() {
var indexToInsert = 0
for forIndex in 0..<sectionsData.count {
// render the tick mark each minute (60 times)
if (sectionsData[forIndex] == "addFaxHeadline") {
indexToInsert = forIndex + 1
}
}
sectionsData.insert("addNewFax", at: indexToInsert)
mainTableView.reloadData()
}
You need to call:
cell.delegate = self
In your cellForRowAtIndex method
This is the common mistake done in protocols and delegates to forget to call delegate.
Here are few examples you can check all have missing is calling delegate:-
Swift delegate beetween two VC without segue
Delegate seems to not be working, according to the console
How to present another view controller after dismiss from navigation controller in swift?
Another way to go inside the vc without protocols
let cell = ///
cell.addButton.tag = indexPath.row
cell.addButton.addTarget(self, action: #selector(buttonTapped(_:)), for: .touchUpInside)
}
#objc func buttonTapped(_ sender:UIButton) {
print(sender.tag)
}
Check that you are doing this:
cell.delegate = self (It's required)
Then improve your line of code like below. Because you will not set delegate then by calling this delegate method directly will get crashed.
#IBAction func onAddFaxNumberPressed(_ sender: Any) {
if let delegateObject = delegate {
delegateObject.faxButtonPressed()
}
}
Second,
In this line, delegateObject.faxButtonPressed(), you will need to send some parameter to identify that will cell is clicked. So you can pass here button tag or you can pass cell also.

How to implement edit/delete behaviour on an embedded tableView?

So I have an embedded tableview and I want to implement edit/delete behaviour:
In my HomePageViewController I have:
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.leftBarButtonItem = editButtonItem
}
However, all that happens is when I click on the edit button, it says done, and the embedded tableview does nothing at all. When I put the above code in the tableview nothing happens.
How do I get the navigation controller/parent view controller to recognise the embedded table view?
It looks like you're using an embed segue to embed a UITableViewController. In your parent view controller, you can do 1 of 2 things easily to achieve you goal.
Method 1: Use the child view controller's edit button
override func viewDidLoad() {
super.viewDidLoad()
// Find and (optionally assign it to a variable for later convenience) the embedded controller, IBOutlets aren't available for VCs embedded within a storyboard
let childControllers = childViewControllers.filter { return $0 is EventTableViewController }
let embeddedController = childControllers[0] as! EventTableViewController
navigationItem.leftBarButtonItem = embeddedController.editButtonItem
}
Method 2: Forward edit events to child view controllers
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.leftBarButtonItem = editButtonItem
}
override func setEditing(_ editing: Bool, animated: Bool) {
super.setEditing(editing, animated: animated)
// Forward editing state to children
childViewControllers.forEach { $0.setEditing(editing, animated: animated) }
}
Note: editButtonItem was exposed in iOS 10 (but was implemented much earlier). For deployment targets less than iOS 10, you can use a custom edit button combined with method 2.
In this situation, you can't use the automatic behavior of the edit button. It's up to you to implement it yourself. You need to toggle both the isEditing of the table view and the appearance of the button. Here's an example from one of my own apps:
func doEdit(_ sender: Any?) {
var which : UIBarButtonSystemItem
if !self.tableView.isEditing {
self.tableView.setEditing(true, animated:true)
which = .done
} else {
self.tableView.setEditing(false, animated:true)
which = .edit
}
let b = UIBarButtonItem(barButtonSystemItem: which,
target: self, action: #selector(doEdit))
self.navigationItem.rightBarButtonItem = b
}

Dismiss keyboard for textfield in uitableviewcell in tableviewcontroller - Swift

I have a textfield and textview in my custom tableviewcell.
I have 4 different prototype cell with 4 different class created. there is a textfield in 1 prototype cell and a textview in the other.
I am not sure how I can do it and I dont understand the obj-c answers out there.
I've tried
override func viewDidLoad() {
super.viewDidLoad()
let tap: UIGestureRecognizer = UIGestureRecognizer(target: self, action: #selector(UIInputViewController.dismissKeyboard))
view.addGestureRecognizer(tap) }
and
func dismissKeyboard() {
self.view.endEditing(true)
}
I wanted to try
UITextFieldDelegate and touchesbegan and textfieldshouldreturn method, but there are no textfields to call in my tableviewcontroller.
Go to attributes inspector in storyboard and click tableView and set keyboard to dismiss interactively.
Or
Set textField delegate and implement
override func viewDidLoad() {
super.viewDidLoad()
textField.delegate = self
}
func textFieldShouldReturn(textField: UITextField) -> Bool // called when 'return' key pressed. return false to ignore.
{
textField.resignFirstResponder()
return true
}
I had same problem, you can solve this with IQKeyboardManager, you don't need to complicate things with the custom cell classes, just install it on your project, when you're all set with installation, in the appDelegate inside the didFinishLaunchingWithOptions method, add this line of code:
IQKeyboardManager.shared.shouldResignOnTouchOutside = true
Get IQKeyboardManager from here.

How to open the keyboard automatically on UITextField?

I have a very simple table and when tocuh a cell it opens a new view with one UITextfield. All I want is that the keyboard will automatically opens, without the user have to touch the UITextfield.
Its all done in Interface Builder, so I am not sure how I do this. I guess I need to set the focus at some point ?
Thanks
To cause the keyboard to show up immediately you'll need to set the text field as the first responder using the following line:
[textField becomeFirstResponder];
You may want to place this in the viewDidAppear: method.
Swift 3 & 4:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
textField.becomeFirstResponder()
}
override func viewDidLoad() {
super.viewDidLoad()
textField.becomeFirstResponder()
}
Prefer adding the first responder on the main thread -
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.textField.becomeFirstResponder()
}
This will come in handy when the view controller view is added as a subview.