I have a tableView that has a header, a footer and a prototype cell for dynamic purposes. I have a Sign Out button in the footer but can't figure out how to get it linked up with a function. I setup a segue to go back to a login page but I want an alert box to ask for confirmation first so I need to somehow call a function.
override func tableView(tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let footerCell = tableView.dequeueReusableCellWithIdentifier("Footer") as! MenuTableViewCell
footerCell.logout.targetForAction("logOutButtonClicked", withSender: self)
return footerCell
}
This is what I have now, but upon click it crashes and gives me
'NSInvalidArgumentException', reason: '-[.MenuTableViewCell logOutButtonClick:]: unrecognized selector sent to instance 0x7ffce28615d0'
I have a function called logOutButtonClicked that looks like this...
func logOutButtonClicked(){
let alertView = UIAlertController(title: "Log Out?", message: "Are you sure you want to Log Out?", preferredStyle: .Alert)
alertView.addAction(UIAlertAction(title: "Cancel", style: .Default, handler: nil))
alertView.addAction(UIAlertAction(title: "Log Out", style: .Default, handler: {(alertAction) -> Void in
self.logOut()}))
presentViewController(alertView, animated: true, completion: nil)
}
func logOut(){
performSegueWithIdentifier("goHome", sender: self)
}
Edit:
I've also tried footerCell.logout.addTarget(self, action: "logOutButtonClicked", forControlEvents: .TouchUpInside)
but that gives the same error as well.
You have to create a function called "logOutButtonClicked" since you specified by adding the targetForAction, it would look something like this:
func logOutButtonClicked() {
}
I managed to fix this problem by erasing all of the events and outlets corresponding to the button (the ones you find when you right click on it) and then rewriting the function like so...
override func tableView(tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let footerCell = tableView.dequeueReusableCellWithIdentifier("Footer") as! MenuTableViewCell
footerCell.logout.addTarget(self, action: "logOutButtonClicked", forControlEvents: .TouchUpInside)
return footerCell
}
Related
I have an AppleWatch App, which receives remote Notifications. I get a callback on my notificationCenter(_:didRecieve response:...) when handling my custom action "a1" and the default action. However, this func isn't called for the custom dismiss action...
class ExtensionDelegate: NSObject, WKExtensionDelegate, UNUserNotificationCenterDelegate {
func applicationDidFinishLaunching() {
// Perform any final initialization of your application.
UNUserNotificationCenter.current().delegate = self
UNUserNotificationCenter.current().requestAuthorization(options: [UNAuthorizationOptions.alert, UNAuthorizationOptions.sound]) { (success, err) in
}
let a1 = UNNotificationAction(identifier: "a1", title: "Do Stuff", options: .foreground)
let c1 = UNNotificationCategory(identifier: "c1", actions: [a1], intentIdentifiers: [], options: .customDismissAction)
UNUserNotificationCenter.current().setNotificationCategories([c1])
}
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
print("Action Identifier: \(response.actionIdentifier)"
completionHandler()
}
}
so my delegate seems to work and the categories too... what am I missing?
Fixed it: if you run your app on the Watch and dismiss it, the notificationCenter(_:didRecieve response:...) of your iOS App's UNUserNotificationCenterDelegate is called (in my case the AppDelegate)!
Probably because when you dismiss it on the watch it is dismissed everywhere...
Didn't find any resources tho.. if you did,
please share the link :)
I need some help! I can't seem to delete just a single row from Parse. I have the "Swipe to delete" figured out, however, when you try and delete something form the table, it doesn't do anything. I get no errors. Nothing gets deleted. This is my code.
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
// delete from server
let myFeatherquery = PFQuery(className: "FeatherPosts")
myFeatherquery.whereKey("message", equalTo: (PFUser.current()?.objectId!)!)
myFeatherquery.findObjectsInBackground(block: { (objects, error) in
if error != nil {
print("THERE WAS AN ERROR")
}else{
for object in objects!{
self.messages.remove(at: indexPath.row)
object.deleteInBackground()
self.tableView.reloadData()
}
}
})
}
}
In short, I want to delete a post from the tableView and delete it on the parse side as well. If I change:
"myFeatherquery.whereKey("message", equalTo: (PFUser.current()?.objectId!)!)"
to
"myFeatherquery.whereKey("userid", equalTo: (PFUser.current()?.objectId!)!)"
it just deleted everything that the user has ever posted. Please help!
You dont need to query inside UITableViewCellEditingStyle becasue IndexPath is already established which one you want to delete.
Now I've added a few extra bit to this logic.
1:) You can slide the cell to view the delete button. Once clicked it will confirm if you want to delete.
2:) Once deleted a fade will take place. It will then refresh the tableView and delete the object in parse in the background.
FeatherPostsArray that you see I made is your array of objects you used in the tableView. In your numberOfRowsInSection you would have done a count on it.
So this is what it should be:
override func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
var recClass = PFObject(className:"FeatherPosts")
recClass = self.FeatherPostsArray[(indexPath as NSIndexPath).row]
let deleteAction = UITableViewRowAction(style: .destructive, title: "Delete") { (action, indexPath) in
let alert = UIAlertController(title: "App Name",
message: "You sure you want to delete?",
preferredStyle: .alert)
let delete = UIAlertAction(title: "Delete", style: .default, handler: { (action) -> Void in
recClass.deleteInBackground {(success, error) -> Void in
if error != nil {
}}
self.FeatherPostsArray.remove(at: (indexPath as NSIndexPath).row)
tableView.deleteRows(at: [indexPath], with: .fade)
tableView.reloadData()
})
let cancel = UIAlertAction(title: "Cancel", style: .destructive, handler: { (action) -> Void in })
alert.addAction(delete)
alert.addAction(cancel)
self.present(alert, animated: true, completion: nil)
}
//This is nice if you want to add a edit button later
return [ deleteAction]
}
Let me know if you get stuck.
The following code worked properly prior to upgrading to Xcode 7.3;
func myMethod() {
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(CreateButtonObject.notifyButtonAction(_:)))
let longPressGesture = UILongPressGestureRecognizer(target: self, action: #selector(CreateButtonObject.notifyButtonAction(_:)))
tapGesture.numberOfTapsRequired = 1
}
#IBAction #objc func notifyButtonAction (sender: AnyObject) {
let userInfo:Dictionary<String,AnyObject!>
print("Sender from tap or longpress: \(sender)")
**let button = sender.view as! UIButton**
let soundName = button.currentTitle!
userInfo = ["sender" : sender]
NSNotificationCenter.defaultCenter().postNotificationName(sleepEZButtonActionNotificationKey, object: nil, userInfo: userInfo)
DDLogDebug("CreateButtonObject.notifyButtonAction: Notificaiton! ButtonViewController")
DDLogDebug("CreateButtonObject.notifyButtonAction: Posted Notification sleepEZButtonActionNotificationKey to initiate buttonAction")
DDLogDebug("CreateButtonObject.notifyButtonAction: Button Name: \(soundName)")
DDLogDebug("")
}
But now when I do this in Xcode 7.3 I get the following error on the line with sender.view ;
Ambiguous use of 'view'
followed by a compiler error.
Anyone know what's going on here and how to fix. Can't figure this out. Basically I need to get the UIButton attributes out of the UITapGesureRecognizer object that is created and then activated on a button press. Stuck.
Thanks in advance...
In the declaration func notifyButtonAction (sender: AnyObject), you have typed sender as AnyObject. But an AnyObject doesn't have a view. So in your line sender.view as! UIButton, the phrase sender.view is illegal.
Type sender as a UIGestureRecognizer if that's what it is: func notifyButtonAction (sender: UIGestureRecognizer). A gesture recognizer does have a view, so all will be well.
My function is this and it is called with a "done" UIBarButtonItem.
#IBAction func done(sender: UIBarButtonItem) {
dismissViewControllerAnimated(true, completion: nil)
}
I have read multiple other questions/answers about a deleted instance or an old/extra connection in the Interface Builder or in the View Controller code. However, I only have this one function all properly connected without any extra lingering connections. How do I get rid of the "unrecognized selector sent to instance" error
Thanks in advance!
With the information provided in the question I suspect
There is unwanted connection left. To see that you can do:
1) Go to the IB and select the button.
2) Right click on the button and see all the actions. If you see any unwanted action delete it and try running again.
You can also do it programmatically
Set the target for UIBarButtonItem like this
var b = UIBarButtonItem(
title: "Continue",
style: .Plain,
target: self,
action: "sayHello:"
)
func sayHello(sender: UIBarButtonItem) {
}
If you dont want any parameters in the sayHello function, you can do it
var b = UIBarButtonItem(
title: "Continue",
style: .Plain,
target: self,
action: "sayHello"// Remove the colon
)
func sayHello() {
}
Let me know if it works for you
Anyone ever had an alert controller with a "cancel" action and just a return in the handler that does something?
Mine goes to the app settings....
I have another alert controller in another viewcontroller that does that. But that shouldn't affect this one????
alertControl.addAction(UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel, handler: { (alertAction) -> Void in
return
}))
update:
Commented all other alertController out. (They were all in other view controller) now it doesn't do it anymore. What is this??
These are also only declared in a function when something goes wrong. When there is no connection,... They shouldn't even exist, unless the function gets called.
update 2 :
func checkAllSettingsForLocation() {
if isTest != true {
//println("should show this")
let alertController = UIAlertController(title: "Scenix can't use your location", message: "Check Location Services under Privacy in the Settings App", preferredStyle: UIAlertControllerStyle.Alert)
let goToSettingsAction = UIAlertAction(title: "Go to Settings", style: .Default, handler: {
action in
UIApplication.sharedApplication().openURL(NSURL(string:UIApplicationOpenSettingsURLString)!)
return
}
)
alertController.addAction(goToSettingsAction)
let ignoreNoCamAction = UIAlertAction(title: "Cancel", style: .Default, handler: {
action in
self.launch = self.launch - 1
return
}
)
alertController.addAction(ignoreNoCamAction)
self.presentViewController(alertController, animated: true, completion: nil)
}
}
Update 3:
Looks more and more like an Xcode Bug.
Building for release / through test flight and the bug is there.
Do a normal debug build and all is fine....
dirty fix =>
Wrap the action from any alert controller in an if statement that checks the alert controller title. Can never throw an exception or result in finding a nil and fixed my problem.
Try using nil instead of return,
let cancel = UIAlertAction(title: "Ok", style: .Cancel, handler: nil)
alertController.addAction(cancel)
I also have some other setting destination alert controllers, and this has worked fine for me.