Add item to segment controller from selecting an action from alert view controller - swift

I had created a normal segment controller which has two category, category 1 and 2 respectively. Now I have add button, which push me to the new view controller to add an item. When clicking on done button for adding an item I have an alert controller which show the category in which I have to save the item. But I don't know how to get that item in particular segment. If anyone can help.
Thanks
#IBAction func done(sender: AnyObject) {
if let item = itemToEdit {
item.text = textField.text!
item.dateTime = dateTime
textField.becomeFirstResponder()
//item.text = textAreaDescription.text!
//textAreaDescription.becomeFirstResponder()
delegate?.itemDetailViewController(self, didFinishEditingItem: item)
} else {
let alertController = UIAlertController(title: "Choose Category", message: "Choose Category To Save Your Item.", preferredStyle: .Alert)
let toDo = UIAlertAction(title: "Category 1", style: .Default) { (action) in
let item = NoToDoItem()
item.text = self.textField.text!
//item.text = textAreaDescription.text!
item.dateTime = self.dateTime
self.delegate?.itemDetailViewController(self, didFinishAddingItem: item)
}
alertController.addAction(toDo)
let notSure = UIAlertAction(title: "Category 2", style: .Default){ (action) in
let notSureItem = NotSureItem()
notSureItem.text = self.textField.text!
//item.text = textAreaDescription.text!
notSureItem.dateTime = self.dateTime
self.delegate?.itemDetailViewController(self, didFinishAddingNotSureItem: notSureItem)
}
alertController.addAction(notSure)
presentViewController(alertController, animated: true, completion: nil)
}
}

use commitEditingstyle, then your cells will still display the Delete button when you swipe. Use editingStyleForRowAtIndexPath: instead. Put an if statement in to test which segment is selected, and return UITableViewCellEditingStyle.None (to disable swipe to delete) or .Delete (to enable swipe to delete) accordingly. If you want to be able to delete the cells by putting the table view into editing mode, then also test tableView.editing to determine whether to use .Delete or .None.

Related

How to add checkmark to submenu of UIMenu in Swift Storyboard?

I'm trying to create a filter option for an app in Swift. Currently, the UI will add a check mark if one of the category filters are selected, such as in the image below for "Food". However, if the "Within Radius" filter is selected, the UI doesn't get updated.
At the moment, this is the code I've written to add the checkmark:
private func updateActionState(actionTitle: String? = nil, menu: UIMenu) -> UIMenu {
if let actionTitle = actionTitle {
menu.children.forEach { action in
guard let action = action as? UIAction else {
return
}
if action.title == actionTitle {
if(action.state == .on){
action.state = .off
}
else{
action.state = .on
}
}
else{
action.state = .off
}
}
} else {
let action = menu.children.first as? UIAction
action?.state = .on
}
return menu
}
I created the menu as follows:
private lazy var elements: [UIAction] = [food, clothing, furniture, other]
private lazy var menu = UIMenu(title: "Category", children: elements)
private lazy var deferredMenu = UIMenu(title: "Distance", options: .displayInline, children: [self.distanceRadius])
override func viewDidLoad() {
super.viewDidLoad()
mapView.delegate = self
loadMap();
menu = menu.replacingChildren([food, clothing, furniture, other, deferredMenu])
navigationItem.leftBarButtonItem?.menu = menu
}
And the UIAction is declared as:
private lazy var distanceRadius = UIAction(title: "Within Radius", attributes: [], state: currFilter == "Within Radius" ? .on : .off){action in
var alert = UIAlertController(title: "Radius", message: "Filter within a radius (in miles)", preferredStyle: .alert)
//2. Add the text field. You can configure it however you need.
alert.addTextField(configurationHandler: { (textField) -> Void in
textField.text = ""
})
//3. Grab the value from the text field, and print it when the user clicks OK.
var radius = 0
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { [weak alert] (action) -> Void in
let textField = (alert?.textFields![0])! as UITextField
radius = Int(textField.text!) ?? 0
self.toggleFilter(actionTitle: "Within Radius", radius: radius)
}))
// 4. Present the alert.
self.present(alert, animated: true, completion: nil)
self.navigationItem.leftBarButtonItem?.menu = self.updateActionState(actionTitle: "Within Radius", menu: self.menu);
}
However, for the "Within Radius" option, the action.title is "Distance", as opposed to "Within Radius", which is what the UIAction is created with. Is there any way to cast a UIAction as a UIMenu to access the children within distanceRadius?
Or is there another way to get the check mark to appear in the Distance submenu?
I've tried re-calling updateActionState on deferredMenu as well but that did not do anything.

UIAlertController is disappearing automatically after short time

If a textfield is empty, I would like to make an UIAlertController to remind, that something has to be filled out in the textfield. Now I have the following code:
#IBAction func saveDetails(segue: UIStoryboardSegue) {
let dController = segue.source as? EntryTableViewController
if let text = dController?.bezeichnungTextField.text, text.isEmpty {
let alert = UIAlertController(title: "No description", message: "Please fill out description", preferredStyle: .alert)
let cancelAction = UIAlertAction(title: "OK", style: .default)
alert.addAction(cancelAction)
self.present(alert, animated: true, completion: nil)
}else {
guard let menge = dController?.mengeTextField.text, let bezeichnung = dController?.bezeichnungTextField.text, let kategorie = dController?.categoryButtonOutlet.titleLabel?.text else {return}
self.saveItem(menge: menge, bezeichnung: bezeichnung, kategorie: kategorie)
self.tableView.reloadData()
}
}
Now actually it works when I press the button to return to the first controller. But the UIAlertController only appears for a very short moment and then disappears automatically. Is there a mistake in my code or isn't it possible to call the UIAlertController on a unwind segue?
Thank you for your help
You just show the alert controller and then immediately unwind. The solution is to check for the empty textfield before unwinding.
Make IBAction for your button then check the textfield if it is empty and then perforn your segue programmatically.

Why is UIPreviewActionStyle destructive title not red?

I am implementing 3D Touch Peek and pop preview actions in my application.
Here is what I have in my ViewController that gets used for the peek and pop.
var previewActions: [UIPreviewAction] {
let item1 = UIPreviewAction(title: "Item1", style: .default) { (action, vc) in
// run item 1 action
}
let item2 = UIPreviewAction(title: "Item2", style: .destructive) { (action, vc) in
// run item 2 action
}
return [item1, item2]
}
The actions are working correctly but the destructive action (item 2) is not displaying the title in red, its still blue.
How can I get the title to display in red like the apple photos app does for the delete button?
I thought the behaviour is the same as UIAlertControllers where destructive is red.
Try to use UIPreviewActionItem instead.
#available(iOS 9.0, *)
override var previewActionItems: [UIPreviewActionItem] {
let item1 = UIPreviewAction(title: "Item1", style: .default) {
(action, vc) in
// run item 1 action
}
let item2 = UIPreviewAction(title: "Item2", style: .destructive) {
(action, vc) in
// run item 2 action
}
return [item1, item2]
}

Update UI in UIAlertAction handler

Could you try to help me to solve the problem of updating the UI of my program while showing the UIAlertView instance?
That's the situation:
I'm pressing the toolbar "hide-button" and the alertView is opening;
In the handler of UIAlertAction (OK button) i have a code, where i make several operations:
remove the toolbar "hide-button" pressed and set the button item with activity indicator instead;
making the indicator rolling;
THEN AND ONLY AFTER PREVIOUS STEPS next part of code should start and the data model is being updated, and because it's connected to the tableView by means of NSFetchedResultsControllerDelegate, the tableView's data is gonna be updated automatically. This step can take some time, so it's extremely needed to hold it asynchronously, and while it's being processed the activity indicator should roll;
after that the activity indicator rolling faults, the toolbar button item with it is being removed and the "hide-button" (removed at the 1st step) comes back.
FINISH.
The problem's with updating the UI, when i exchange "hide-button" and "activity-button".
private var hideDataBarButtonItem: UIBarButtonItem?
private var indicatorBarButtonItem = UIBarButtonItem(customView: UIActivityIndicatorView(activityIndicatorStyle: .Gray))
override func viewDidLoad() {
super.viewDidLoad()
...
hideDataBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Stop, target: self, action: #selector(hideAllLoginData))
toolbarItems?.insert(hideDataBarButtonItem!, atIndex: 2)
}
That's the action for hideDataBarButtonItem:
#IBAction func hideAllLoginData(sender: AnyObject) {
let confirmAlert = UIAlertController(title: "Hide all data?", message: "", preferredStyle: .Alert)
confirmAlert.addAction( UIAlertAction(title: "OK", style: .Default, handler: { action in
// remove the clear-button, set the indicator button instead and start indicator rolling
self.toolbarItems?.removeAtIndex(2)
self.toolbarItems?.insert(self.indicatorBarButtonItem, atIndex: 2)
(self.indicatorBarButtonItem.customView as! UIActivityIndicatorView).startAnimating()
print("button with indicator added")
sleep(5) // -> CHECK: this moment indicator should be visible and rolling!
dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0)) {
for section in self.resources {
for resource in section {
if resource.defRecord != nil {
resource.defRecord = nil
}
}
}
print("data cleared")
dispatch_async(dispatch_get_main_queue()) {
// remove indicator and set the clear-button back
print("button with indicator removed")
(self.indicatorBarButtonItem.customView as! UIActivityIndicatorView).stopAnimating()
self.toolbarItems?.removeAtIndex(2)
self.toolbarItems?.insert(self.hideDataBarButtonItem!, atIndex: 2)
}
}
}) )
confirmAlert.addAction( UIAlertAction(title: "Cancel", style: .Cancel, handler: nil ) )
self.presentViewController(confirmAlert, animated: true, completion: nil)
}
The result of the execution:
button with indicator added
// -> 5 sec of awaiting, but that's nothing in interface changed!
data cleared
button with indicator removed
If i don't remove the indicator button, i can see it after all, but it has to appear earlier. What do i make wrong?
Thank you!
The problem's solved.
It was because the NSFetchedResultsController updated the UI not in the main thread. I had to deactivate it's delegate while my model was updating. Then, in the main thread i has to activate it again and update the tableView data. The solution is here (look at the comments):
dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0)) {
// clear the delegate in order to not to allow UI update by fetchedResultsController
self.resourceModel.nullifyFetchedResultsControllerDelegate()
for section in self.resources {
for resource in section {
if resource.defRecord != nil {
resource.defRecord = nil
}
}
}
print("data cleared")
dispatch_async(dispatch_get_main_queue()) {
// set the delegate back and update the tableView
self.resourceModel.setFetchedResultsControllerDelegate(self)
self.reloadResources()
self.tableView.reloadData()
// remove indicator and set the clear-button back
print("button with indicator removed")
(self.indicatorBarButtonItem.customView as! UIActivityIndicatorView).stopAnimating()
self.toolbarItems?.removeAtIndex(2)
self.toolbarItems?.insert(self.hideDataBarButtonItem!, atIndex: 2)
}
}
PeterK, thank you for your advices!

swipe tableViewCell to delete an item

I want to delete a Unit from my Core Data Application. When user presses delete button on the Cell, I present a warning.
the code was
let alert = UIAlertController(title: "Warning!", message: "Are you sure to delete \"\(currentUnit)\" and all of its containing objects?", preferredStyle: .Alert)
I wanted to update the warning message with the objects count so I wrote
currentUnitObjectsCount = getSelectedUnitObjectsCount() //Which connects to database and returns just an integer
let deleteAction = UITableViewRowAction(style: UITableViewRowActionStyle.Default, title: "Delete",handler: { (action, indexPath) -> Void in
let currentUnit = self.units[indexPath.row].title!
let alert = UIAlertController(title: "Warning!", message: "Are you sure to delete \"\(currentUnit)\" and all of its \(currentUnitObjectsCount) containing objects?", preferredStyle: .Alert)
let yesAction = UIAlertAction(title: "Yes", style: .Default) /* handler: { (action : UIAlertAction) -> Void in */ { (action : UIAlertAction) in
if let managedObjectContext = (UIApplication.sharedApplication().delegate as? AppDelegate)?.managedObjectContext{
let unitToDelete = self.fetchResultController.objectAtIndexPath(indexPath) as! Unit
managedObjectContext.deleteObject(unitToDelete)
do{
try managedObjectContext.save()
}catch{
print(error)
}
}
self.checkUnits()
}
let noAction = UIAlertAction(title: "No", style: UIAlertActionStyle.Default, handler: {
(action : UIAlertAction!) -> Void in
tableView.reloadData() //to return the tableView to its normal view
})
alert.addAction(yesAction)
alert.addAction(noAction)
self.presentViewController(alert, animated: true, completion: nil)
})
deleteAction.backgroundColor = UIColor.redColor()
return [editAction]
}
Now when i swipe the tableViewCell, it swipes but the delete button does not appear but when I tap the Delete button position in the swiped cell, the warning appears which means the button is there but I cant see it.
returning the code to the first style every thing works fine, but the second one acts very strange.
When I put this line of code
currentUnitObjectsCount = getSelectedUnitObjectsCount() //Which connects to database and returns just an integer
just after the the
let deleteAction = ...
currentUnitObjectsCount = getSelectedUnitObjectsCount()
let currentUnit = self.units[indexPath.row].title!
.
.
.
and swipe a cell, rows of the table disappear
I dont find why these happen.